Aaron Turon <aturon@mozilla.com>
Aaron Weiss <aaronweiss74@gmail.com>
Abhishek Chanda <abhishek.becs@gmail.com>
+Adam Badawy <adambada@buffalo.edu>
Adam Bozanich <adam.boz@gmail.com>
+Adam Crume <adamcrume@gmail.com>
Adam Heins <mail@adamheins.com>
Adam Jacob <adam@opscode.com>
Adam Roben <adam@roben.org>
Alan Williams <mralert@gmail.com>
Aleksander Balicki <balicki.aleksander@gmail.com>
Aleksandr Koshlo <sash7ko@gmail.com>
+Aleksey Kladov <aleksey.kladov@gmail.com>
Alexander Artemenko <svetlyak.40wt@gmail.com>
Alexander Bliskovsky <alexander.bliskovsky@gmail.com>
+Alexander Bulaev <aleks.bulaev@gmail.com>
Alexander Campbell <alexanderhcampbell@gmail.com>
Alexander Chernyakhovsky <achernya@mit.edu>
Alexander Korolkov <alexander.korolkov@gmail.com>
Alexandros Tasos <sdi1100085@di.uoa.gr>
Alex Burka <durka42+github@gmail.com>
Alex Crichton <alex@alexcrichton.com>
+AlexDenisov <1101.debian@gmail.com>
Alexei Sholik <alcosholik@gmail.com>
Alex Gaynor <alex.gaynor@gmail.com>
Alexis Beingessner <a.beingessner@gmail.com>
Alex Lyon <arcterus@mail.com>
Alex Newman <posix4e@gmail.com>
+Alex Ozdemir <aozdemir@hmc.edu>
Alex Quach <alex@clinkle.com>
Alex Rønne Petersen <alex@lycus.org>
Alex Stokes <r.alex.stokes@gmail.com>
Alex Whitney <aw1209@ic.ac.uk>
Alfie John <alfie@alfie.wtf>
+Alfie John <alfiej@fastmail.fm>
Alisdair Owens <awo101@zepler.net>
Ali Smesseim <smesseim.ali@gmail.com>
Aljaž "g5pw" Srebrnič <a2piratesoft@gmail.com>
+Amanieu d'Antras <amanieu@gmail.com>
+Amit Aryeh Levy <amit@amitlevy.com>
+Amit Saha <amitsaha@users.noreply.github.com>
Amol Mundayoor <amol.com@gmail.com>
Amy Unger <amy.e.unger@gmail.com>
Anatoly Ikorsky <aikorsky@gmail.com>
Andreas Martens <andreasm@fastmail.fm>
Andreas Neuhaus <zargony@zargony.com>
Andreas Ots <andreasots@gmail.com>
+Andreas Sommer <andreas.sommer87@googlemail.com>
Andreas Tolfsen <ato@mozilla.com>
+Andre Bogus <bogusandre@gmail.com>
Andrei Formiga <archimedes_siracusa@hotmail.com>
Andrei Oprea <andrei.br92@gmail.com>
Andrew Barchuk <raindev@icloud.com>
Andrew Seidl <dev@aas.io>
Andrew Straw <strawman@astraw.com>
Andrew Wagner <drewm1980@gmail.com>
+androm3da <brian.cain@gmail.com>
Andrzej Janik <vosen@vosen.pl>
Andy Caldwell <andrew.caldwell@metaswitch.com>
Andy Grover <agrover@redhat.com>
+angelsl <hidingfromhidden@gmail.com>
Angus Lees <gus@inodes.org>
Anthony Juckel <ajuckel@gmail.com>
Anton Löfgren <anton.lofgren@gmail.com>
Antti Keränen <detegr@gmail.com>
+aochagavia <aochagavia92@gmail.com>
Aram Visser <aramvisser@gmail.com>
+arcnmx <arcnmx@users.noreply.github.com>
Arcterus <Arcterus@mail.com>
Areski Belaid <areski@gmail.com>
Ariel Ben-Yehuda <arielb1@mail.tau.ac.il>
Armin Ronacher <armin.ronacher@active-4.com>
Arpad Borsos <arpad.borsos@googlemail.com>
Artem <artemciy@gmail.com>
+Artem Shitov <artemshitov@yandex-team.ru>
Arthur Liao <arthurtw8@gmail.com>
arthurprs <arthurprs@gmail.com>
arturo <arturo@openframeworks.cc>
+Ashkan Kiani <ashkan.k.kiani@gmail.com>
Ashok Gautham <ScriptDevil@gmail.com>
Augusto Hack <hack.augusto@gmail.com>
auREAX <mark@xn--hwg34fba.ws>
awlnx <alecweber1994@gmail.com>
Axel Viala <axel.viala@darnuria.eu>
Aydin Kim <ladinjin@hanmail.net>
+b1nd <clint.ryan3@gmail.com>
bachm <Ab@vapor.com>
+Barosl LEE <github@barosl.com>
Barosl Lee <vcs@barosl.com>
+Bastien Dejean <nihilhill@gmail.com>
bcoopers <coopersmithbrian@gmail.com>
Ben Alpert <ben@benalpert.com>
benaryorg <binary@benary.org>
Ben Kelly <ben@wanderview.com>
Ben Noordhuis <info@bnoordhuis.nl>
Ben Sago <ogham@users.noreply.github.com>
+benshu <benshu@benshu.de>
+Ben S <ogham@users.noreply.github.com>
Ben Striegel <ben.striegel@gmail.com>
+Bhargav Patel <bhargavrpatel@users.noreply.github.com>
Bheesham Persaud <bheesham123@hotmail.com>
Bilal Husain <bilal@bilalhusain.com>
Bill Fallon <bill.fallon@robos.li>
Bill Myers <bill_myers@outlook.com>
+billpmurphy <billpmurphy92@gmail.com>
Bill Wendling <wendling@apple.com>
Birunthan Mohanathas <birunthan@mohanathas.com>
Björn Steinbrink <bsteinbr@gmail.com>
+blackbeam <aikorsky@gmail.com>
blake2-ppc <ulrik.sverdrup@gmail.com>
Blake Loring <Blake.Loring@ig.com>
-bluss <bluss>
bluss <bluss@users.noreply.github.com>
-Boris Egorov <egorov@linux.com>
+bombless <bombless@126.com>
+Boris Egorov <jightuse@gmail.com>
bors <bors@rust-lang.org>
Bouke van der Bijl <boukevanderbijl@gmail.com>
Brad King <brad.king@kitware.com>
Brian Quinlan <brian@sweetapp.com>
Brody Holden <brody.holden.r@gmail.com>
Bruno de Oliveira Abinader <bruno.d@partner.samsung.com>
+Bruno Tavares <connect+github@bltavares.com>
Bryan Dunsmore <dunsmoreb@gmail.com>
+Bryce Van Dyk <bryce@vandyk.net.nz>
Byron Williams <byron@112percent.com>
Cadence Marseille <cadencemarseille@gmail.com>
+caipre <platt.nicholas@gmail.com>
Caitlin Potter <snowball@defpixel.com>
+Cameron Sun <cameron.csun@gmail.com>
Cameron Zwarich <zwarich@mozilla.com>
Camille Roussel <camille@rousselfamily.com>
Camille TJHOA <camille.tjhoa@outlook.com>
Carl-Anton Ingmarsson <mail@carlanton.se>
Carl Lerche <me@carllerche.com>
Carlos Galarza <carloslfu@gmail.com>
+Carlos Liam <carlos@aarzee.me>
+Carlos <toqueteos@gmail.com>
Carol (Nichols || Goulding) <carol.nichols@gmail.com>
Carol Willing <carolcode@willingconsulting.com>
Carter Hinsley <carterhinsley@gmail.com>
Carter Tazio Schonwald <carter.schonwald@gmail.com>
CarVac <c.lo.to.da.down.lo@gmail.com>
Caspar Krieger <caspar@asparck.com>
+Cesar Eduardo Barros <cesarb@cesarb.eti.br>
+Charlotte Spencer <charlottelaspencer@gmail.com>
Chase Southwood <chase.southwood@gmail.com>
Ches Martin <ches@whiskeyandgrits.net>
-chitra
+chitra <bogus>
Chloe <5paceToast@users.noreply.github.com>
+Chris C Cerami <chrisccerami@users.noreply.github.com>
Chris Double <chris.double@double.co.nz>
+Chris Drake <cjdrake@gmail.com>
Chris Hellmuth <chellmuth@gmail.com>
+Chris Krycho <chris@krycho.com>
Chris Morgan <me@chrismorgan.info>
Chris Nixon <chris.nixon@sigma.me.uk>
Chris Peterson <cpeterson@mozilla.com>
Christoph Burgdorf <christoph.burgdorf@bvsn.org>
Christopher Bergqvist <spambox0@digitalpoetry.se>
Christopher Chambers <chris.chambers@peanutcode.com>
+christopherdumas <christopherdumas@me.com>
Christopher Kendell <ckendell@outlook.com>
Chris Wong <lambda.fairy@gmail.com>
chromatic <chromatic@wgz.org>
Cole Reynolds <cpjreynolds@gmail.com>
Colin Davidson <colrdavidson@gmail.com>
Colin Sherratt <colin.sherratt@gmail.com>
+Colin Wallace <wallacoloo@gmail.com>
Colin Walters <walters@verbum.org>
comex <comexk@gmail.com>
Conrad Kleinespel <conradk@conradk.com>
+corentih <corentin.henry@alcatel-lucent.com>
+Corentin Henry <corentinhenry@gmail.com>
Corey Farwell <coreyf+rust@rwell.org>
Corey Ford <corey@coreyford.name>
Corey Richardson <corey@octayn.net>
Cornel Punga <cornel.punga@gmail.com>
+Craig Hills <chills@gmail.com>
crhino <piraino.chris@gmail.com>
Cristian Kubis <cristian.kubis@tsunix.de>
Cristi Burcă <scribu@gmail.com>
+Cristi Cobzarenco <cristi.cobzarenco@gmail.com>
critiqjo <john.ch.fr@gmail.com>
Cruz Julian Bishop <cruzjbishop@gmail.com>
+Daan Rijks <daanrijks@gmail.com>
+Dabo Ross <daboross@daboross.net>
Damian Gryski <damian@gryski.com>
Damien Grassart <damien@grassart.com>
Damien Radtke <dradtke@channeliq.com>
Dan Connolly <dckc@madmode.com>
Daniel Albert <albert_daniel@t-online.de>
Daniel Brooks <db48x@db48x.net>
+Daniel Carral <dan@dcarral.org>
Daniel Fagnan <dnfagnan@gmail.com>
Daniel Farina <daniel@fdr.io>
Daniel Griffen <daniel@dgriffen.com>
Daniel Grunwald <daniel@danielgrunwald.de>
Daniel Hofstetter <daniel.hofstetter@42dh.com>
+Daniel Keep <daniel.keep@gmail.com>
Daniel Lobato García <elobatocs@gmail.com>
Daniel Luz <dev@mernen.com>
Daniel MacDougall <dmacdougall@gmail.com>
Daniel Raloff <draloff@side2.com>
Daniel Ralston <Wubbulous@gmail.com>
Daniel Ramos <dan@daramos.com>
+Daniel Rollins <drollins@financialforce.com>
Daniel Rosenwasser <DanielRosenwasser@gmail.com>
+Daniel Trebbien <dtrebbien@gmail.com>
Daniel Ursache Dogariu <contact@danniel.net>
Daniil Smirnov <danslapman@gmail.com>
+Danilo Bargen <mail@dbrgn.ch>
Dan Luu <danluu@gmail.com>
Dan Schatzberg <schatzberg.dan@gmail.com>
Dan W. <1danwade@gmail.com>
Darin Morrison <darinmorrison+git@gmail.com>
darkf <lw9k123@gmail.com>
Darrell Hamilton <darrell.noice@gmail.com>
+Dato Simó <dato@net.com.org.es>
Dave Herman <dherman@mozilla.com>
Dave Hodder <dmh@dmh.org.uk>
Dave Huseby <dhuseby@mozilla.com>
David Campbell <dcampbell24@gmail.com>
David Creswick <dcrewi@gyrae.net>
+David Elliott <david@gophilosophie.com>
David Forsythe <dforsythe@gmail.com>
David Halperin <halperin.dr@gmail.com>
David King <dave@davbo.org>
David Rajchenbach-Teller <dteller@mozilla.com>
David Reid <dreid@dreid.org>
David Renshaw <dwrenshaw@gmail.com>
+David Ripton <dripton@ripton.net>
David Ross <daboross@daboross.net>
David Stygstra <david.stygstra@gmail.com>
+David Szotten <davidszotten@gmail.com>
David Vazgenovich Shakaryan <dvshakaryan@gmail.com>
David Voit <david.voit@gmail.com>
Davis Silverman <sinistersnare@gmail.com>
defuz <defuz.net@gmail.com>
Denis Defreyne <denis.defreyne@stoneship.org>
+DenisKolodin <DenisKolodin@gmail.com>
Derecho <derecho@sector5d.org>
Derek Chiang <derekchiang93@gmail.com>
Derek Guenther <dguenther9@gmail.com>
Derek Harland <derek.harland@finq.co.nz>
+Devon Hollowood <devonhollowood@gmail.com>
dgoon <dgoon@dgoon.net>
diaphore <diaphore@gmail.com>
Diego Giagio <diego@giagio.com>
Dominick Allen <dominick.allen1989@gmail.com>
Dominic van Berkel <dominic@baudvine.net>
Dominik Inführ <dominik.infuehr@gmail.com>
+Dongie Agnir <dongie.agnir@gmail.com>
+Dong Zhou <dong.zhou.08@gmail.com>
Do Nhat Minh <mrordinaire@gmail.com>
donkopotamus <general@chocolate-fish.com>
Donovan Preston <donovanpreston@gmail.com>
Don Petersen <don@donpetersen.net>
+Doug Goldstein <cardoe@cardoe.com>
Douglas Young <rcxdude@gmail.com>
Drew Crawford <drew@sealedabstract.com>
Drew Willcoxon <adw@mozilla.com>
Duncan Regan <duncanregan@gmail.com>
Dylan Braithwaite <dylanbraithwaite1@gmail.com>
Dylan Ede <dylanede@googlemail.com>
+Dylan McKay <dylanmckay34@gmail.com>
Dzmitry Malyshau <kvarkus@gmail.com>
Earl St Sauver <estsauver@gmail.com>
+ebadf <brian.cain@gmail.com>
econoplas <econoplas@gmail.com>
Eduard Bopp <eduard.bopp@aepsil0n.de>
Eduard Burtescu <edy.burt@gmail.com>
Elly Fong-Jones <elly@leptoquark.net>
elszben <notgonna@tellyou>
emanueLczirai <emanueLczirai@cryptoLab.net>
+Emanuel Czirai <zazdxscf@gmail.com>
Emanuel Rylke <ema-fox@web.de>
Emeliov Dmitrii <demelev1990@gmail.com>
Emilio Cobos Álvarez <ecoal95@gmail.com>
Emily Dunham <edunham@mozilla.com>
Eric Allen <ericpallen@gmail.com>
Eric Biggers <ebiggers3@gmail.com>
+Eric Findlay <e.findlay@protonmail.com>
Eric Holk <eric.holk@gmail.com>
Eric Holmes <eric@ejholmes.net>
Eric Kidd <git@randomhacks.net>
Eric Platon <eric.platon@waku-waku.ne.jp>
Eric Reed <ecreed@cs.washington.edu>
Eric Ye <me@ericye16.com>
+Erik Davidson <erik@erikd.org>
Erik Lyon <elyon001@local.fake>
Erik Michaels-Ober <sferik@gmail.com>
Erik Price <erik.price16@gmail.com>
Eunji Jeong <eun-ji.jeong@samsung.com>
Evan Klitzke <evan@eklitzke.org>
Evan McClanahan <evan@evanmcc.com>
-Evgeny Sologubov
+Evgeny Sologubov <bogus>
Fabian Deutsch <fabian.deutsch@gmx.de>
+Fabiano Beselga <fabianobeselga@gmail.com>
Fabrice Desré <fabrice@desre.org>
FakeKane <andrewyli@gmail.com>
Falco Hirschenberger <falco.hirschenberger@gmail.com>
fenduru <fenduru@users.noreply.github.com>
Fenhl <fenhl@fenhl.net>
Filip Szczepański <jazz2rulez@gmail.com>
-Flaper Fesp <flaper87@gmail.com>
+Flavio Percoco <flaper87@gmail.com>
flo-l <lacknerflo@gmail.com>
Florian Gilcher <florian.gilcher@asquera.de>
Florian Hahn <flo@fhahn.com>
Gil Cottle <rc@redtown.org>
Gioele Barabucci <gioele@svario.it>
github-monoculture <eocene@gmx.com>
+GlacJAY <glacjay@gmail.com>
Gleb Kozyrev <gleb@gkoz.com>
+glendc <decauwsemaecker.glen@gmail.com>
Glenn Willen <gwillen@nerdnet.org>
Gonçalo Cabrita <_@gmcabrita.com>
Grahame Bowland <grahame@angrygoats.net>
-Graham Fawcett <graham.fawcett@gmail.com>
+Graham Fawcett <fawcett@uwindsor.ca>
Graydon Hoare <graydon@pobox.com>
Greg Chapple <gregchapple1@gmail.com>
Grigoriy <ohaistarlight@gmail.com>
Huachao Huang <huachao.huang@gmail.com>
Hugo Jobling <hello@thisishugo.com>
Hugo van der Wijst <hugo@wij.st>
+Hunan Rostomyan <hunan131@gmail.com>
Huon Wilson <dbau.pp+github@gmail.com>
Hyeon Kim <simnalamburt@gmail.com>
Ian Connolly <iconnolly@mozilla.com>
Ian D. Bollinger <ian.bollinger@gmail.com>
Ignacio Corderi <icorderi@msn.com>
Igor Bukanov <igor@mir2.org>
+Igor Shuvalov <i.s.shuvalov@gmail.com>
Igor Strebezhev <xamgore@ya.ru>
Ilya Dmitrichenko <ilya@xively.com>
Ilyong Cho <ilyoan@gmail.com>
Ingo Blechschmidt <iblech@web.de>
inrustwetrust <inrustwetrust@users.noreply.github.com>
+Irving A.J. Rivas Z. <axel.rivas@gmail.com>
Isaac Aggrey <isaac.aggrey@gmail.com>
Isaac Dupree <antispam@idupree.com>
Isaac Ge <acgtyrant@gmail.com>
Ivan Enderlin <ivan.enderlin@hoa-project.net>
+Ivan Ivaschenko <defuz.net@gmail.com>
+Ivan Jager <aij+git@mrph.org>
+Ivan Kozik <ivan@ludios.org>
Ivano Coppola <rgbfirefox@gmail.com>
Ivan Petkov <ivanppetkov@gmail.com>
Ivan Radanov Ivanov <ivanradanov@yahoo.co.uk>
+Ivan Stankovic <pokemon@fly.srk.fer.hr>
Ivan Ukhov <ivan.ukhov@gmail.com>
Iven Hsu <ivenvd@gmail.com>
+Jack Fransham <moonfudgeman@hotmail.co.uk>
Jack Heizer <jack.heizer@gmail.com>
Jack Moffitt <jack@metajack.im>
+Jack Wilson <jack.wilson.v@gmail.com>
Jacob Edelman <edelman.jd@gmail.com>
Jacob Harris Cryer Kragh <jhckragh@gmail.com>
Jacob Hegna <jacobhegna@gmail.com>
Jake Kaufman <theevocater@gmail.com>
Jake Kerr <kodafox@gmail.com>
Jake Scott <jake.net@gmail.com>
+Jake Shadle <jake.shadle@frostbite.com>
+Jake Worth <jakeworth82@gmail.com>
Jakub Bukaj <jakub@jakub.cc>
Jakub Vrána <jakub@vrana.cz>
Jakub Wieczorek <jakubw@jakubw.net>
+James Bell <james.bell@gmail.com>
James Deng <cnjamesdeng@gmail.com>
James Hurst <jamesrhurst@users.noreply.github.com>
James Lal <james@lightsofapollo.com>
James Laverack <james@jameslaverack.com>
jamesluke <jamesluke@users.noreply.github.com>
+James McGlashan <github@darkfox.id.au>
James Miller <bladeon@gmail.com>
James Perry <james.austin.perry@gmail.com>
James Rowe <jroweboy@gmail.com>
J Bailey <jj2baile@uwaterloo.ca>
jbranchaud <jbranchaud@gmail.com>
J.C. Moyer <jmoyer1992@gmail.com>
+Jean Maillard <jeanm@users.noreply.github.com>
Jeaye <jeaye@arrownext.com>
Jed Davis <jld@panix.com>
Jed Estep <aje@jhu.edu>
Jeff Muizelaar <jmuizelaar@mozilla.com>
Jeff Olson <olson.jeffery@gmail.com>
Jeff Parsons <jeffdougson@gmail.com>
+Jeffrey Seyfried <jeffrey.seyfried@gmail.com>
Jeffrey Yasskin <jyasskin@gmail.com>
Jelte Fennema <github-tech@jeltef.nl>
Jens Nockert <jens@nockert.se>
Jesse Ruderman <jruderman@gmail.com>
Jessy Diamond Exum <jessy.diamondman@gmail.com>
Jesús Espino <jespinog@gmail.com>
+Jethro Beekman <jethro@jbeekman.nl>
jethrogb <github@jbeekman.nl>
Jexell <Jexell@users.noreply.github.com>
Jihyeok Seo <me@limeburst.net>
-Jihyun Yu <j.yu@navercorp.com>
+Jihyun Yu <jihyun@nclab.kaist.ac.kr>
Jim Apple <jbapple+rust@google.com>
Jim Blandy <jimb@red-bean.com>
Jimmie Elvenmark <flugsio@gmail.com>
jmgrosen <jmgrosen@gmail.com>
jmu303 <muj@bc.edu>
João Oliveira <hello@jxs.pt>
+joaoxsouls <joaoxsouls@gmail.com>
Joe Pletcher <joepletcher@gmail.com>
Joe Schafer <joe@jschaf.com>
Johannes Hoff <johshoff@gmail.com>
Johannes Löthberg <johannes@kyriasis.com>
Johannes Muenzel <jmuenzel@gmail.com>
Johannes Oertel <johannes.oertel@uni-due.de>
-Johann Hofmann <git@johann-hofmann.com>
+Johann Hofmann <mail@johann-hofmann.com>
Johann Tuffe <tafia973@gmail.com>
John Albietz <inthecloud247@gmail.com>
John Barker <jebarker@gmail.com>
John Schmidt <john.schmidt.h@gmail.com>
John Simon <john@johnsoft.com>
John Talling <inrustwetrust@users.noreply.github.com>
+John Thomas <thomas07@vt.edu>
John Van Enk <vanenkj@gmail.com>
John Zhang <john@zhang.io>
joliv <joliv@users.noreply.github.com>
Jonas Hietala <tradet.h@gmail.com>
+Jonas Schievink <jonas@schievink.net>
Jonathan Bailey <jbailey@mozilla.com>
Jonathan Boyett <jonathan@failingservers.com>
Jonathan Hansford <dangthrimble@hansfords.net>
Jordan Humphreys <mrsweaters@users.noreply.github.com>
Jordan Woehr <jordanwoehr@gmail.com>
Jordi Boggiano <j.boggiano@seld.be>
-Jorge Aparicio <japaricious@gmail.com>
+Jorge Aparicio <japaric@linux.com>
Jorge Israel Peña <jorge.israel.p@gmail.com>
Joris Rehm <joris.rehm@wakusei.fr>
Jormundir <Chaseph@gmail.com>
+Jørn Lode <jlode90@gmail.com>
Jose Narvaez <jnarvaez@zendesk.com>
+Joseph Caudle <joseph@josephcaudle.com>
Joseph Crail <jbcrail@gmail.com>
Joseph Martin <pythoner6@gmail.com>
Joseph Rushton Wakeling <joe@webdrake.net>
+Josh Austin <josh.austin@gmail.com>
Josh Haberman <jhaberman@gmail.com>
Josh Matthews <josh@joshmatthews.net>
Josh Stone <cuviper@gmail.com>
Josh Triplett <josh@joshtriplett.org>
Joshua Clark <joshua.clark@txstate.edu>
+Joshua Holmer <holmerj@uindy.edu>
Joshua Landau <joshua@landau.ws>
Joshua Wise <joshua@joshuawise.com>
Joshua Yanovski <pythonesque@gmail.com>
+jotomicron <jotomicron@gmail.com>
JP-Ellis <coujellis@gmail.com>
JP Sugarbroad <jpsugar@google.com>
+jrburke <jrburke@gmail.com>
jrincayc <jrincayc@users.noreply.github.com>
+J. Ryan Stinnett <jryans@gmail.com>
Julia Evans <julia@jvns.ca>
Julian Orth <ju.orth@gmail.com>
Julian Viereck <julian.viereck@gmail.com>
Kevin Rauwolf <sweetpea-git@tentacle.net>
Kevin Walter <kevin.walter.private@googlemail.com>
Kevin Yap <me@kevinyap.ca>
+Kevin Yeh <kevinyeah@utexas.edu>
kgv <mail@kgv.name>
+kickinbahk <kickinbahk@gmail.com>
Kieran Hunt <kieran.hunt92@gmail.com>
Kiet Tran <ktt3ja@gmail.com>
Kim Røen <kim@pam.no>
kjpgit <kjpgit@users.noreply.github.com>
klutzy <klutzytheklutzy@gmail.com>
+Kohei Hasegawa <ameutau@gmail.com>
KokaKiwi <kokakiwi+rust@kokakiwi.net>
korenchkin <korenchkin2@gmail.com>
Kornel Lesiński <kornel@geekhood.net>
kulakowski <george.kulakowski@gmail.com>
kwantam <kwantam@gmail.com>
Kyeongwoon Lee <kyeongwoon.lee@samsung.com>
+Kyle Mayes <kyle@mayeses.com>
+Kyle Robinson Young <kyle@dontkry.com>
Lai Jiangshan <laijs@cn.fujitsu.com>
Lars Bergstrom <lbergstrom@mozilla.com>
Laurence Tratt <laurie@tratt.net>
Leah Hanson <astrieanna@gmail.com>
Lee Aronson <lee@libertad.ucsd.edu>
Lee Jeffery <leejeffery@gmail.com>
+Lee Jenkins <cljenkins9@gmail.com>
Lee Wondong <wdlee91@gmail.com>
Leif Arne Storset <leifarne@storset.net>
LemmingAvalanche <haugsbakk@yahoo.no>
Liigo Zhuang <com.liigo@gmail.com>
Lindsey Kuper <lindsey@composition.al>
Lionel Flandrin <lionel.flandrin@parrot.com>
+llogiq <bogusandre@gmail.com>
Logan Chien <tzuhsiang.chien@gmail.com>
Loïc Damien <loic.damien@dzamlo.ch>
Lorenz <lorenzb@student.ethz.ch>
Makoto Nakashima <makoto.nksm+github@gmail.com>
Manish Goregaokar <manishsmail@gmail.com>
Manuel Hoffmann <manuel@polythematik.de>
+Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
marcell <marcell.pardavi@gmail.com>
+Marcello Seri <marcello.seri@gmail.com>
+Marcell Pardavi <marcell.pardavi@gmail.com>
Marcel Müller <neikos@neikos.email>
Marcel Rodrigues <marcelgmr@gmail.com>
Marcus Klaas <mail@marcusklaas.nl>
Mark Buer <mark.buer@booktrack.com>
Mark Lacey <641@rudkx.com>
Mark Mossberg <mark.mossberg@gmail.com>
+Marko Lalic <marko.lalic@gmail.com>
Mark Rowe <mrowe@bdash.net.nz>
Mark Sinclair <mark.edward.x@gmail.com>
Markus Siemens <siemens1993@gmail.com>
Martin DeMello <martindemello@gmail.com>
Martin Olsson <martin@minimum.se>
Martin Pool <mbp@sourcefrog.net>
+Martin Wernstål <m4rw3r@gmail.com>
Marti Raudsepp <marti@juffo.org>
Marvin Löbel <loebel.marvin@gmail.com>
masklinn <github.com@masklinn.net>
+Matěj Grabovský <mgrabovsky@yahoo.com>
Matej Lach <matej.lach@gmail.com>
Mateusz Czapliński <czapkofan@gmail.com>
Mathieu David <mathieudavid@mathieudavid.org>
Matthew Iselin <matthew@theiselins.net>
Matthew McPherrin <matthew@mcpherrin.ca>
Matthew O'Connor <thegreendragon@gmail.com>
+Matthias Bussonnier <bussonniermatthias@gmail.com>
Matthias Einwag <matthias.einwag@live.com>
+Matthias Kauer <mk.software@zuez.org>
Matthijs Hofstra <thiezz@gmail.com>
Matthijs van der Vleuten <git@zr40.nl>
Matt McPherrin <git@mcpherrin.ca>
Michael Arntzenius <daekharel@gmail.com>
Michael Bebenita <mbebenita@mozilla.com>
Michael Budde <mbudde@gmail.com>
+Michael Choate <choatemd@miamioh.edu>
Michael Dagitses <dagitses@google.com>
Michael Darakananda <pongad@gmail.com>
Michael Fairley <michaelfairley@gmail.com>
Michael Gehring <mg@ebfe.org>
+Michael Howell <michael@notriddle.com>
Michael Kainer <kaini1123@gmail.com>
Michael Layzell <michael@thelayzells.com>
Michael Letterle <michael.letterle@gmail.com>
Michael Macias <zaeleus@gmail.com>
Michael Matuzak <mmatuzak@gmail.com>
+Michael McConville <mmcconville@mykolab.com>
Michael Neumann <mneumann@ntecs.de>
Michael Pankov <work@michaelpankov.com>
Michael Park <mcypark@gmail.com>
Mickaël Salaün <mic@digikod.net>
Mick Koch <kchmck@gmail.com>
midinastasurazz <mpavlovsky@gmail.com>
+Mihaly Barasz <klao@nilcons.com>
Mihnea Dobrescu-Balaur <mihnea@linux.com>
Mike Boutin <mike.boutin@gmail.com>
Mike Dilger <mike@efx.co.nz>
Mike English <mike.english@atomicobject.com>
+Mike Marcacci <mike.marcacci@gmail.com>
Mike Pedersen <noctune9@gmail.com>
Mike Robinson <mikeprobinsonuk@gmail.com>
Mike Sampson <mike@sambodata.com>
Nathan Froyd <froydnj@gmail.com>
Nathaniel Herman <nherman@post.harvard.edu>
Nathaniel Theis <nttheis@gmail.com>
+Nathan Kleyn <nathan@nathankleyn.com>
Nathan Long <nathanmlong@gmail.com>
Nathan Stoddard <nstodda@purdue.edu>
Nathan Typanski <ntypanski@gmail.com>
Neil Pankey <npankey@gmail.com>
Nelo Onyiah <nelo.onyiah@gmail.com>
Nelson Chen <crazysim@gmail.com>
+nham <hamann.nick@gmail.com>
NiccosSystem <niccossystem@gmail.com>
Nicholas Bishop <nicholasbishop@gmail.com>
Nicholas Mazzuca <npmazzuca@gmail.com>
+Nicholas Seckar <nseckar@gmail.com>
Nick Cameron <ncameron@mozilla.com>
Nick Desaulniers <ndesaulniers@mozilla.com>
Nick Fitzgerald <fitzgen@gmail.com>
Nif Ward <nif.ward@gmail.com>
Nikita Pekin <contact@nikitapek.in>
Niklas Koep <niklas.koep@gmail.com>
+Nikolay Kondratyev <nkondratyev@yandex.ru>
Niko Matsakis <niko@alum.mit.edu>
Nils Liberg <nils@nilsliberg.se>
Nils Winter <nils.winter@gmail.com>
+Niranjan Padmanabhan <niranjan.padmanabhan@cloudera.com>
noam <noam@clusterfoo.com>
Noam Yorav-Raphael <noamraph@gmail.com>
NODA, Kai <nodakai@gmail.com>
novalis <novalis@novalis.org>
nsf <no.smile.face@gmail.com>
nwin <nwin@users.noreply.github.com>
+nxnfufunezn <nxnfufunezn@gmail.com>
Oak <White-Oak@users.noreply.github.com>
OGINO Masanori <masanori.ogino@gmail.com>
OlegTsyba <idethrone1@gmail.com>
-Oliver Schneider <git1984941651981@oli-obk.de>
+Ole Krüger <ole@kru.gr>
+Oliver Middleton <olliemail27@gmail.com>
+Oliver Schneider <oliver.schneider@kit.edu>
Olivier Saut <osaut@airpost.net>
olivren <o.renaud@gmx.fr>
Olle Jonsson <olle.jonsson@gmail.com>
olombard <lombard-olivier@bbox.fr>
Or Brostovski <tohava@gmail.com>
Oren Hazi <oren.hazi@gmail.com>
+Ori Avtalion <ori@avtalion.name>
Or Neeman <oneeman@gmail.com>
Orphée Lafond-Lummis <o@orftz.com>
Orpheus Lummis <o@orpheuslummis.com>
osa1 <omeragacan@gmail.com>
O S K Chaitanya <osk@medhas.org>
+Overmind JIANG <p90eri@gmail.com>
Ožbolt Menegatti <ozbolt.menegatti@gmail.com>
P1start <rewi-github@whanau.org>
Pablo Brasero <pablo@pablobm.com>
Palmer Cox <p@lmercox.com>
+panicbit <panicbit.dev@gmail.com>
Paolo Falabella <paolo.falabella@gmail.com>
Parker Moore <parkrmoore@gmail.com>
Pascal Hertleif <killercup@gmail.com>
Patrick Yevsukov <patrickyevsukov@users.noreply.github.com>
Patrik Kårlin <patrik.karlin@gmail.com>
Paul ADENOT <paul@paul.cx>
+Paul A. Jungwirth <pj@illuminatedcomputing.com>
Paul Banks <banks@banksdesigns.co.uk>
Paul Collier <paul@paulcollier.ca>
Paul Collins <paul@ondioline.org>
Peter Hull <peterhull90@gmail.com>
Peter Marheine <peter@taricorp.net>
Peter Minten <peter@pminten.nl>
+Peter Reid <peter.d.reid@gmail.com>
Peter Schuller <peter.schuller@infidyne.com>
Peter Williams <peter@newton.cx>
Peter Zotov <whitequark@whitequark.org>
Philip Munksgaard <pmunksgaard@gmail.com>
Philipp Brüschweiler <blei42@gmail.com>
Philipp Gesang <phg42.2a@gmail.com>
+Philipp Matthias Schäfer <philipp.matthias.schaefer@posteo.de>
+Philipp Oppermann <dev@phil-opp.com>
Phil Ruffwind <rf@rufflewind.com>
Pierre Baillet <pierre@baillet.name>
+pierzchalski <e.a.pierzchalski@gmail.com>
Piotr Czarnecki <pioczarn@gmail.com>
Piotr Jawniak <sawyer47@gmail.com>
Piotr Szotkowski <chastell@chastell.net>
Poga Po <poga.bahamut@gmail.com>
posixphreak <posixphreak@gmail.com>
Potpourri <pot_pourri@mail.ru>
+Pradeep Kumar <gohanpra@gmail.com>
Prudhvi Krishna Surapaneni <me@prudhvi.net>
Przemysław Wesołek <jest@go.art.pl>
Pyfisch <pyfisch@gmail.com>
Pyry Kontio <pyry.kontio@drasa.eu>
+Pythoner6 <pythoner6@gmail.com>
Q.P.Liu <qpliu@yahoo.com>
qwitwa <qwitwa@gmail.com>
Rafael Ávila de Espíndola <respindola@mozilla.com>
Raphael Nestler <raphael.nestler@gmail.com>
Raphael Speyer <rspeyer@gmail.com>
Raul Gutierrez S <rgs@itevenworks.net>
+Ravi Shankar <wafflespeanut@gmail.com>
Ray Clanan <rclanan@utopianconcept.com>
ray glover <ray@rayglover.net>
reedlepee <reedlepee123@gmail.com>
Remi Rampin <remirampin@gmail.com>
Renato Alves <alves.rjc@gmail.com>
Renato Riccieri Santos Zannon <renato@rrsz.com.br>
+Renato Zannon <renato@rrsz.com.br>
Reuben Morais <reuben.morais@gmail.com>
reus <reusee@ymail.com>
+Reza Akhavan <reza@akhavan.me>
Ricardo Martins <ricardo@scarybox.net>
Ricardo M. Correia <rcorreia@wizy.org>
+Ricardo Signes <rjbs@cpan.org>
Richard Diamond <wichard@vitalitystudios.com>
Rich Lane <rlane@club.cc.cmu.edu>
Richo Healey <richo@psych0tik.net>
Rick Waldron <waldron.rick@gmail.com>
Ricky Taylor <rickytaylor26@gmail.com>
+Rizky Luthfianto <mrluthfianto@gmail.com>
rjz <rj@rjzaworski.com>
Rob Arnold <robarnold@cs.cmu.edu>
Robert Buonpastore <robert.buonpastore@gmail.com>
Robert Clipsham <robert@octarineparrot.com>
Robert Foss <dev@robertfoss.se>
+Robert Gardner <rhg259@nyu.edu>
Robert Gawdzik <rgawdzik@hotmail.com>
Robert Irelan <rirelan@gmail.com>
Robert Knight <robertknight@gmail.com>
Rory O’Kane <rory@roryokane.com>
Roy Crihfield <rscrihf@gmail.com>
Roy Frostig <rfrostig@mozilla.com>
+Ruby <hi@ruby.sh>
Rüdiger Sonderfeld <ruediger@c-plusplus.de>
rundrop1 <rundrop1@zoho.com>
Russell Johnston <rpjohnst@gmail.com>
Ryan Scheel <ryan.havvy@gmail.com>
Ryman <haqkrs@gmail.com>
らいどっと <ryogo.yoshimura@gmail.com>
+Ryo Munakata <afpacket@gmail.com>
Sae-bom Kim <sae-bom.kim@samsung.com>
Salem Talha <salem.a.talha@gmail.com>
saml <saml@users.noreply.github.com>
Sean Stangl <sstangl@mozilla.com>
Sean T Allen <sean@monkeysnatchbanana.com>
Sebastian Gesemann <s.gesemann@gmail.com>
+Sebastian Hahn <sebastian@torproject.org>
Sebastian N. Fernandez <cachobot@gmail.com>
Sebastian Rasmussen <sebras@gmail.com>
+Sebastian Wicki <gandro@gmx.net>
Sebastian Zaha <sebastian.zaha@gmail.com>
Sébastien Chauvel <eichi237@mailoo.org>
Sébastien Crozet <developer@crozet.re>
Sébastien Marie <semarie@users.noreply.github.com>
Sebastien Martini <seb@dbzteam.org>
Sébastien Paolacci <sebastien.paolacci@gmail.com>
+Seeker14491 <seeker14491@gmail.com>
Seonghyun Kim <sh8281.kim@samsung.com>
Seo Sanghyeon <sanxiyn@gmail.com>
Sergio Benitez <sbenitez@mit.edu>
Simonas Kazlauskas <git@kazlauskas.me>
Simon Barber-Dueck <sbarberdueck@gmail.com>
Simon Kern <simon.kern@rwth-aachen.de>
+Simon Mazur <semmaz.box@gmail.com>
Simon Persson <simon@flaskpost.org>
Simon Sapin <simon@exyr.org>
Simon Wollwage <mail.wollwage@gmail.com>
simplex <theemptystring@gmail.com>
Sindre Johansen <sindre@sindrejohansen.no>
sinkuu <sinkuupump@gmail.com>
+skeleten <janpelle.thomson@stud.tu-darmstadt.de>
Skyler <skyler.lipthay@gmail.com>
smenardpw <sebastien@knoglr.com>
Son <leson.phung@gmail.com>
Squeaky <squeaky_pl@gmx.com>
startling <tdixon51793@gmail.com>
Stefan Bucur <stefan.bucur@epfl.ch>
+Stefan O'Rear <stefanor@cox.net>
Stefan Plantikow <stefan.plantikow@googlemail.com>
Stepan Koltsov <stepan.koltsov@gmail.com>
Sterling Greene <sterling.greene@gmail.com>
tav <tav@espians.com>
Taylor Hutchison <seanthutchison@gmail.com>
Ted Horst <ted.horst@earthlink.net>
+Ted Mielczarek <ted@mielczarek.org>
Tero Hänninen <lgvz@users.noreply.github.com>
+Tero Hänninen <tejohann@kapsi.fi>
th0114nd <th0114nd@gmail.com>
Thad Guidry <thadguidry@gmail.com>
Theo Belaire <theo.belaire@gmail.com>
Tim Brooks <brooks@cern.ch>
Tim Chevalier <chevalier@alum.wellesley.edu>
Tim Cuthbertson <tim@gfxmonk.net>
+Tim Dumol <tim@timdumol.com>
+Tim JIANG <p90eri@gmail.com>
Tim Joseph Dumol <tim@timdumol.com>
Tim Kuehn <tkuehn@cmu.edu>
+Tim Neumann <mail@timnn.me>
Timon Rapp <timon@zaeda.net>
Timothée Ravier <tim@siosm.fr>
Tim Parenti <timparenti@gmail.com>
Ty Overby <ty@pre-alpha.com>
Ulrik Sverdrup <bluss@users.noreply.github.com>
Ulysse Carion <ulysse@ulysse.io>
+U-NOV2010\eugals <bogus>
User Jyyou <jyyou@plaslab.cs.nctu.edu.tw>
Utkarsh Kukreti <utkarshkukreti@gmail.com>
Uwe Dauernheim <uwe@dauernheim.net>
Vadim Petrochenkov <vadim.petrochenkov@gmail.com>
Valentin Tsatskin <vtsatskin@mozilla.com>
Valerii Hiora <valerii.hiora@gmail.com>
+Viacheslav Chimishuk <Viacheslav.Chemishuk@keystonett.com>
Victor Berger <victor.berger@m4x.org>
Victor van den Elzen <victor.vde@gmail.com>
Victory <git@dfhu.org>
Vladimir Smola <smola.vladimir@gmail.com>
Vojtech Kral <vojtech@kral.hk>
Volker Mische <volker.mische@gmail.com>
+w00ns <w00ns@w00ns.top>
Wade Mealing <wmealing@gmail.com>
Wangshan Lu <wisagan@gmail.com>
WebeWizard <webewizard@gmail.com>
William Throwe <wtt6@cornell.edu>
William Ting <io@williamting.com>
Willson Mock <willson.mock@gmail.com>
+Will Speak <lithiumflame@gmail.com>
Will <will@glozer.net>
+Willy Aguirre <marti1125@gmail.com>
+Without Boats <woboats@gmail.com>
Wojciech Ogrodowczyk <github@haikuco.de>
wonyong kim <wonyong.kim@samsung.com>
xales <xales@naveria.com>
+Xavier Shay <xavier@rhnh.net>
+xd1le <elisp.vim@gmail.com>
+Xiao Chuan Yu <xcyu.se@gmail.com>
Xuefeng Wu <benewu@gmail.com>
XuefengWu <benewu@gmail.com>
Xuefeng Wu <xfwu@thoughtworks.com>
Yehuda Katz <wycats@gmail.com>
Yongqian Li <yongqli@kerrmetric.com>
York Xiang <bombless@126.com>
+Yoshito Komatsu <ykomatsu@akaumigame.org>
Young-il Choi <duddlf.choi@samsung.com>
Youngmin Yoo <youngmin.yoo@samsung.com>
Youngsoo Son <ysson83@gmail.com>
the other rollup-eligible patches too, and they'll get tested and merged at
the same time.
-To find documentation-related issues, sort by the [A-docs label][adocs].
+To find documentation-related issues, sort by the [A-docs label][adocs].
[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs
+In many cases, you don't need a full `make doc`. You can use `rustdoc` directly
+to check small fixes. For example, `rustdoc src/doc/reference.md` will render
+reference to `doc/reference.html`. The CSS might be messed up, but you can
+verify that HTML is right.
+
## Issue Triage
Sometimes, an issue will stay open, even though the bug has been fixed. And
labels to triage issues:
* Yellow, **A**-prefixed labels state which **area** of the project an issue
- relates to.
+ relates to.
-* Magenta, **B**-prefixed labels identify bugs which **belong** elsewhere.
+* Magenta, **B**-prefixed labels identify bugs which **belong** elsewhere.
* Green, **E**-prefixed labels explain the level of **experience** necessary
to fix the issue.
* Red, **I**-prefixed labels indicate the **importance** of the issue. The
[I-nominated][inom] label indicates that an issue has been nominated for
- prioritizing at the next triage meeting.
+ prioritizing at the next triage meeting.
* Orange, **P**-prefixed labels indicate a bug's **priority**. These labels
are only assigned during triage meetings, and replace the [I-nominated][inom]
- label.
+ label.
* Blue, **T**-prefixed bugs denote which **team** the issue belongs to.
* Dark blue, **beta-** labels track changes which need to be backported into
- the beta branches.
-
+ the beta branches.
+
* The purple **metabug** label marks lists of bugs collected by other
- categories.
+ categories.
-If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
+If you're looking for somewhere to start, check out the [E-easy][eeasy] tag.
[inom]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AI-nominated
[eeasy]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy
* The [Rust Internals forum][rif], a place to ask questions and
discuss Rust's internals
* The [generated documentation for rust's compiler][gdfrustc]
-* The [rust referance][rr], even though it doesn't specifically talk about Rust's internals, its a great reasource nontheless
+* The [rust reference][rr], even though it doesn't specifically talk about Rust's internals, it's a great resource nonetheless
* Although out of date, [Tom Lee's great blog article][tlgba] is very helpful
* [rustaceans.org][ro] is helpful, but mostly dedicated to IRC
* The [Rust Compiler Testing Docs][rctd]
-* For @bors, [this cheetsheat][cheetsheat] is helpful (Remember to replace `@homu` with `@bors` in the commands that you use.)
-* **Google**!
+* For @bors, [this cheat sheet][cheatsheet] is helpful (Remember to replace `@homu` with `@bors` in the commands that you use.)
+* **Google!** ([search only in Rust Documentation][gsearchdocs] to find types, traits, etc. quickly)
* Don't be afraid to ask! The Rust community is friendly and helpful.
[gdfrustc]: http://manishearth.github.io/rust-internals-docs/rustc/
+[gsearchdocs]: https://www.google.de/search?q=site:doc.rust-lang.org+your+query+here
[rif]: http://internals.rust-lang.org
[rr]: https://doc.rust-lang.org/book/README.html
[tlgba]: http://tomlee.co/2014/04/03/a-more-detailed-tour-of-the-rust-compiler/
[ro]: http://www.rustaceans.org/
[rctd]: ./COMPILER_TESTS.md
-[cheetsheat]: http://buildbot.rust-lang.org/homu/
+[cheatsheet]: http://buildbot.rust-lang.org/homu/
#
# * check - Run the complete test suite
#
-# * clean - Clean the build repertory. It is advised to run this
+# * clean - Clean the build repository. It is advised to run this
# command if you want to build Rust again, after an update
# of the git repository.
#
```sh
# Update package mirrors (may be needed if you have a fresh install of MSYS2)
$ pacman -Sy pacman-mirrors
-
+
# Choose one based on platform:
$ pacman -S mingw-w64-i686-toolchain
$ pacman -S mingw-w64-x86_64-toolchain
+ # Make git available in MSYS2 (if not already available on path)
+ $ pacman -S git
+
$ pacman -S base-devel
```
$ ./configure
$ make && make install
```
+> ***Note:*** gcc versions >= 5 currently have issues building LLVM on Windows
+> resulting in a segmentation fault when building Rust. In order to avoid this
+> it may be necessary to obtain an earlier version of gcc such as 4.9.x.
+> Installers for earlier Windows builds of gcc are available at the
+> [Mingw-Builds] project. For more information on this see issue #28260.
+
+[Mingw-Builds]: http://sourceforge.net/projects/mingw-w64/
## Building Documentation
details will apply. Once you have the compiler built, you can
```sh
-$ make docs NO_REBUILD=1
+$ make docs NO_REBUILD=1
```
To make sure you don’t re-build the compiler because you made a change
-Version 1.4.0 (October 2015)
-============================
+Version 1.5.0 (2015-12-10)
+==========================
+
+* ~700 changes, numerous bugfixes
+
+Highlights
+----------
+
+* Stabilized APIs:
+ [`BinaryHeap::from`], [`BinaryHeap::into_sorted_vec`],
+ [`BinaryHeap::into_vec`], [`Condvar::wait_timeout`],
+ [`FileTypeExt::is_block_device`], [`FileTypeExt::is_char_device`],
+ [`FileTypeExt::is_fifo`], [`FileTypeExt::is_socket`],
+ [`FileTypeExt`], [`Formatter::alternate`], [`Formatter::fill`],
+ [`Formatter::precision`], [`Formatter::sign_aware_zero_pad`],
+ [`Formatter::sign_minus`], [`Formatter::sign_plus`],
+ [`Formatter::width`], [`Iterator::cmp`], [`Iterator::eq`],
+ [`Iterator::ge`], [`Iterator::gt`], [`Iterator::le`],
+ [`Iterator::lt`], [`Iterator::ne`], [`Iterator::partial_cmp`],
+ [`Path::canonicalize`], [`Path::exists`], [`Path::is_dir`],
+ [`Path::is_file`], [`Path::metadata`], [`Path::read_dir`],
+ [`Path::read_link`], [`Path::symlink_metadata`],
+ [`Utf8Error::valid_up_to`], [`Vec::resize`],
+ [`VecDeque::as_mut_slices`], [`VecDeque::as_slices`],
+ [`VecDeque::insert`], [`VecDeque::shrink_to_fit`],
+ [`VecDeque::swap_remove_back`], [`VecDeque::swap_remove_front`],
+ [`slice::split_first_mut`], [`slice::split_first`],
+ [`slice::split_last_mut`], [`slice::split_last`],
+ [`char::from_u32_unchecked`], [`fs::canonicalize`],
+ [`str::MatchIndices`], [`str::RMatchIndices`],
+ [`str::match_indices`], [`str::rmatch_indices`],
+ [`str::slice_mut_unchecked`], [`string::ParseError`].
+* Rust applications hosted on crates.io can be installed locally to
+ `~/.cargo/bin` with the [`cargo install`] command. Among other
+ things this makes it easier to augment Cargo with new subcommands:
+ when a binary named e.g. `cargo-foo` is found in `$PATH` it can be
+ invoked as `cargo foo`.
+* Crates with wildcard (`*`) dependencies will [emit warnings when
+ published][1.5w]. In 1.6 it will no longer be possible to publish
+ crates with wildcard dependencies.
+
+Breaking Changes
+----------------
+
+* The rules determining when a particular lifetime must outlive
+ a particular value (known as '[dropck]') have been [modified
+ to not rely on parametricity][1.5p].
+* [Implementations of `AsRef` and `AsMut` were added to `Box`, `Rc`,
+ and `Arc`][1.5a]. Because these smart pointer types implement
+ `Deref`, this causes breakage in cases where the interior type
+ contains methods of the same name.
+* [Correct a bug in Rc/Arc][1.5c] that caused [dropck] to be unaware
+ that they could drop their content. Soundness fix.
+* All method invocations are [properly checked][1.5wf1] for
+ [well-formedness][1.5wf2]. Soundness fix.
+* Traits whose supertraits contain `Self` are [not object
+ safe][1.5o]. Soundness fix.
+* Target specifications support a [`no_default_libraries`][1.5nd]
+ setting that controls whether `-nodefaultlibs` is passed to the
+ linker, and in turn the `is_like_windows` setting no longer affects
+ the `-nodefaultlibs` flag.
+* `#[derive(Show)]`, long-deprecated, [has been removed][1.5ds].
+* The `#[inline]` and `#[repr]` attributes [can only appear
+ in valid locations][1.5at].
+* Native libraries linked from the local crate are [passed to
+ the linker before native libraries from upstream crates][1.5nl].
+* Two rarely-used attributes, `#[no_debug]` and
+ `#[omit_gdb_pretty_printer_section]` [are feature gated][1.5fg].
+* Negation of unsigned integers, which has been a warning for
+ several releases, [is now behind a feature gate and will
+ generate errors][1.5nu].
+* The parser accidentally accepted visibility modifiers on
+ enum variants, a bug [which has been fixed][1.5ev].
+* [A bug was fixed that allowed `use` statements to import unstable
+ features][1.5use].
+
+Language
+--------
+
+* When evaluating expressions at compile-time that are not
+ compile-time constants (const-evaluating expressions in non-const
+ contexts), incorrect code such as overlong bitshifts and arithmetic
+ overflow will [generate a warning instead of an error][1.5ce],
+ delaying the error until runtime. This will allow the
+ const-evaluator to be expanded in the future backwards-compatibly.
+* The `improper_ctypes` lint [no longer warns about using `isize` and
+ `usize` in FFI][1.5ict].
+
+Libraries
+---------
+
+* `Arc<T>` and `Rc<T>` are [covariant with respect to `T` instead of
+ invariant][1.5c].
+* `Default` is [implemented for mutable slices][1.5d].
+* `FromStr` is [implemented for `SockAddrV4` and `SockAddrV6`][1.5s].
+* There are now `From` conversions [between floating point
+ types][1.5f] where the conversions are lossless.
+* Thera are now `From` conversions [between integer types][1.5i] where
+ the conversions are lossless.
+* [`fs::Metadata` implements `Clone`][1.5fs].
+* The `parse` method [accepts a leading "+" when parsing
+ integers][1.5pi].
+* [`AsMut` is implemented for `Vec`][1.5am].
+* The `clone_from` implementations for `String` and `BinaryHeap` [have
+ been optimized][1.5cf] and no longer rely on the default impl.
+* The `extern "Rust"`, `extern "C"`, `unsafe extern "Rust"` and
+ `unsafe extern "C"` function types now [implement `Clone`,
+ `PartialEq`, `Eq`, `PartialOrd`, `Ord`, `Hash`, `fmt::Pointer`, and
+ `fmt::Debug` for up to 12 arguments][1.5fp].
+* [Dropping `Vec`s is much faster in unoptimized builds when the
+ element types don't implement `Drop`][1.5dv].
+* A bug that caused in incorrect behavior when [combining `VecDeque`
+ with zero-sized types][1.5vdz] was resolved.
+* [`PartialOrd` for slices is faster][1.5po].
+
+Miscellaneous
+-------------
+
+* [Crate metadata size was reduced by 20%][1.5md].
+* [Improvements to code generation reduced the size of libcore by 3.3
+ MB and rustc's memory usage by 18MB][1.5m].
+* [Improvements to deref translation increased performance in
+ unoptimized builds][1.5dr].
+* Various errors in trait resolution [are deduplicated to only be
+ reported once][1.5te].
+* Rust has preliminary [support for rumprun kernels][1.5rr].
+* Rust has preliminary [support for NetBSD on amd64][1.5na].
+
+[1.5use]: https://github.com/rust-lang/rust/pull/28364
+[1.5po]: https://github.com/rust-lang/rust/pull/28436
+[1.5ev]: https://github.com/rust-lang/rust/pull/28442
+[1.5nu]: https://github.com/rust-lang/rust/pull/28468
+[1.5dr]: https://github.com/rust-lang/rust/pull/28491
+[1.5vdz]: https://github.com/rust-lang/rust/pull/28494
+[1.5md]: https://github.com/rust-lang/rust/pull/28521
+[1.5fg]: https://github.com/rust-lang/rust/pull/28522
+[1.5dv]: https://github.com/rust-lang/rust/pull/28531
+[1.5na]: https://github.com/rust-lang/rust/pull/28543
+[1.5fp]: https://github.com/rust-lang/rust/pull/28560
+[1.5rr]: https://github.com/rust-lang/rust/pull/28593
+[1.5cf]: https://github.com/rust-lang/rust/pull/28602
+[1.5nl]: https://github.com/rust-lang/rust/pull/28605
+[1.5te]: https://github.com/rust-lang/rust/pull/28645
+[1.5at]: https://github.com/rust-lang/rust/pull/28650
+[1.5am]: https://github.com/rust-lang/rust/pull/28663
+[1.5m]: https://github.com/rust-lang/rust/pull/28778
+[1.5ict]: https://github.com/rust-lang/rust/pull/28779
+[1.5a]: https://github.com/rust-lang/rust/pull/28811
+[1.5pi]: https://github.com/rust-lang/rust/pull/28826
+[1.5ce]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
+[1.5p]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
+[1.5i]: https://github.com/rust-lang/rust/pull/28921
+[1.5fs]: https://github.com/rust-lang/rust/pull/29021
+[1.5f]: https://github.com/rust-lang/rust/pull/29129
+[1.5ds]: https://github.com/rust-lang/rust/pull/29148
+[1.5s]: https://github.com/rust-lang/rust/pull/29190
+[1.5d]: https://github.com/rust-lang/rust/pull/29245
+[1.5o]: https://github.com/rust-lang/rust/pull/29259
+[1.5nd]: https://github.com/rust-lang/rust/pull/28578
+[1.5wf2]: https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md
+[1.5wf1]: https://github.com/rust-lang/rust/pull/28669
+[dropck]: https://doc.rust-lang.org/nightly/nomicon/dropck.html
+[1.5c]: https://github.com/rust-lang/rust/pull/29110
+[1.5w]: https://github.com/rust-lang/rfcs/blob/master/text/1241-no-wildcard-deps.md
+[`cargo install`]: https://github.com/rust-lang/rfcs/blob/master/text/1200-cargo-install.md
+[`BinaryHeap::from`]: http://doc.rust-lang.org/nightly/std/convert/trait.From.html#method.from
+[`BinaryHeap::into_sorted_vec`]: http://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html#method.into_sorted_vec
+[`BinaryHeap::into_vec`]: http://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html#method.into_vec
+[`Condvar::wait_timeout`]: http://doc.rust-lang.org/nightly/std/sync/struct.Condvar.html#method.wait_timeout
+[`FileTypeExt::is_block_device`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_block_device
+[`FileTypeExt::is_char_device`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_char_device
+[`FileTypeExt::is_fifo`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_fifo
+[`FileTypeExt::is_socket`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html#tymethod.is_socket
+[`FileTypeExt`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/trait.FileTypeExt.html
+[`Formatter::alternate`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.alternate
+[`Formatter::fill`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.fill
+[`Formatter::precision`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.precision
+[`Formatter::sign_aware_zero_pad`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.sign_aware_zero_pad
+[`Formatter::sign_minus`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.sign_minus
+[`Formatter::sign_plus`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.sign_plus
+[`Formatter::width`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.width
+[`Iterator::cmp`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.cmp
+[`Iterator::eq`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.eq
+[`Iterator::ge`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.ge
+[`Iterator::gt`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.gt
+[`Iterator::le`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.le
+[`Iterator::lt`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.lt
+[`Iterator::ne`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.ne
+[`Iterator::partial_cmp`]: http://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#method.partial_cmp
+[`Path::canonicalize`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.canonicalize
+[`Path::exists`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.exists
+[`Path::is_dir`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.is_dir
+[`Path::is_file`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.is_file
+[`Path::metadata`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.metadata
+[`Path::read_dir`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.read_dir
+[`Path::read_link`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.read_link
+[`Path::symlink_metadata`]: http://doc.rust-lang.org/nightly/std/path/struct.Path.html#method.symlink_metadata
+[`Utf8Error::valid_up_to`]: http://doc.rust-lang.org/nightly/core/str/struct.Utf8Error.html#method.valid_up_to
+[`Vec::resize`]: http://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.resize
+[`VecDeque::as_mut_slices`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.as_mut_slices
+[`VecDeque::as_slices`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.as_slices
+[`VecDeque::insert`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.insert
+[`VecDeque::shrink_to_fit`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.shrink_to_fit
+[`VecDeque::swap_remove_back`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.swap_remove_back
+[`VecDeque::swap_remove_front`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.swap_remove_front
+[`slice::split_first_mut`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_first_mut
+[`slice::split_first`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_first
+[`slice::split_last_mut`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_last_mut
+[`slice::split_last`]: http://doc.rust-lang.org/nightly/std/primitive.slice.html#method.split_last
+[`char::from_u32_unchecked`]: http://doc.rust-lang.org/nightly/std/char/fn.from_u32_unchecked.html
+[`fs::canonicalize`]: http://doc.rust-lang.org/nightly/std/fs/fn.canonicalize.html
+[`str::MatchIndices`]: http://doc.rust-lang.org/nightly/std/str/struct.MatchIndices.html
+[`str::RMatchIndices`]: http://doc.rust-lang.org/nightly/std/str/struct.RMatchIndices.html
+[`str::match_indices`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.match_indices
+[`str::rmatch_indices`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.rmatch_indices
+[`str::slice_mut_unchecked`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.slice_mut_unchecked
+[`string::ParseError`]: http://doc.rust-lang.org/nightly/std/string/enum.ParseError.html
+
+Version 1.4.0 (2015-10-29)
+==========================
* ~1200 changes, numerous bugfixes
* [The `str::lines` and `BufRead::lines` iterators treat `\r\n` as
line breaks in addition to `\n`][crlf].
* [Loans of `'static` lifetime extend to the end of a function][stat].
+* [`str::parse` no longer introduces avoidable rounding error when
+ parsing floating point numbers. Together with earlier changes to
+ float formatting/output, "round trips" like f.to_string().parse()
+ now preserve the value of f exactly. Additionally, leading plus
+ signs are now accepted][fp3].
+
Language
--------
prelude][pr].
* [`Extend<String>` and `FromIterator<String` are both implemented for
`String`][es].
-* [`IntoIterator` is implemented for `Option<&T>` and
- `Result<&T>`][into].
+* [`IntoIterator` is implemented for references to `Option` and
+ `Result`][into2].
* [`HashMap` and `HashSet` implement `Extend<&T>` where `T:
- Copy`][ext] as part of [RFC 839].
+ Copy`][ext] as part of [RFC 839]. This will cause type inferance
+ breakage in rare situations.
* [`BinaryHeap` implements `Debug`][bh2].
* [`Borrow` and `BorrowMut` are implemented for fixed-size
arrays][bm].
-* [`extern fn`s of with the "Rust" and "C" ABIs implement common
+* [`extern fn`s with the "Rust" and "C" ABIs implement common
traits including `Eq`, `Ord`, `Debug`, `Hash`][fp].
* [String comparison is faster][faststr].
-* `&mut T` where `T: Write` [also implements `Write`][mutw].
-* [A stable regression in `VecDec::push_back` that caused panics for
- zero-sized types was fixed][vd].
+* `&mut T` where `T: std::fmt::Write` [also implements
+ `std::fmt::Write`][mutw].
+* [A stable regression in `VecDeque::push_back` and other
+ capicity-altering methods that caused panics for zero-sized types
+ was fixed][vd].
* [Function pointers implement traits for up to 12 parameters][fp2].
Miscellaneous
[ffi]: https://github.com/rust-lang/rust/pull/28779
[fp]: https://github.com/rust-lang/rust/pull/28268
[fp2]: https://github.com/rust-lang/rust/pull/28560
+[fp3]: https://github.com/rust-lang/rust/pull/27307
[i]: https://github.com/rust-lang/rust/pull/27451
-[into]: https://github.com/rust-lang/rust/pull/28039
+[into2]: https://github.com/rust-lang/rust/pull/28039
[it]: https://github.com/rust-lang/rust/pull/27652
[mm]: https://github.com/rust-lang/rust/pull/27338
[mutw]: https://github.com/rust-lang/rust/pull/28368
[path-normalize]: https://github.com/rust-lang/rust/pull/23229
-Version 1.0.0-alpha.2 (February 2015)
+Version 1.0.0-alpha.2 (2015-02-20)
=====================================
* ~1300 changes, numerous bugfixes
[un]: https://github.com/rust-lang/rust/pull/22256
-Version 1.0.0-alpha (January 2015)
+Version 1.0.0-alpha (2015-01-09)
==================================
* ~2400 changes, numerous bugfixes
[rbe]: http://rustbyexample.com/
-Version 0.12.0 (October 2014)
+Version 0.12.0 (2014-10-09)
=============================
* ~1900 changes, numerous bugfixes
kernels and distributions, built on CentOS 5.10.
-Version 0.11.0 (July 2014)
+Version 0.11.0 (2014-07-02)
==========================
* ~1700 changes, numerous bugfixes
greatly improved.
-Version 0.10 (April 2014)
+Version 0.10 (2014-04-03)
=========================
* ~1500 changes, numerous bugfixes
directory.
-Version 0.9 (January 2014)
+Version 0.9 (2014-01-09)
==========================
* ~1800 changes, numerous bugfixes
build tools.
-Version 0.8 (September 2013)
+Version 0.8 (2013-09-26)
============================
* ~2200 changes, numerous bugfixes
still invoked through the normal `rustdoc` command.
-Version 0.7 (July 2013)
+Version 0.7 (2013-07-03)
=======================
* ~2000 changes, numerous bugfixes
* Improvements to rustpkg (see the detailed release notes).
-Version 0.6 (April 2013)
+Version 0.6 (2013-04-03)
========================
* ~2100 changes, numerous bugfixes
* Inline assembler supported by new asm!() syntax extension.
-Version 0.5 (December 2012)
+Version 0.5 (2012-12-21)
===========================
* ~900 changes, numerous bugfixes
* License changed from MIT to dual MIT/APL2
-Version 0.4 (October 2012)
+Version 0.4 (2012-10-15)
==========================
* ~2000 changes, numerous bugfixes
* All hash functions and tables converted to secure, randomized SipHash
-Version 0.3 (July 2012)
+Version 0.3 (2012-07-12)
========================
* ~1900 changes, numerous bugfixes
* Cargo automatically resolves dependencies
-Version 0.2 (March 2012)
+Version 0.2 (2012-03-29)
=========================
* >1500 changes, numerous bugfixes
* Extensive cleanup, regularization in libstd, libcore
-Version 0.1 (January 20, 2012)
+Version 0.1 (2012-01-20)
===============================
* Most language features work, including:
opt local-rust 0 "use an installed rustc rather than downloading a snapshot"
opt llvm-static-stdcpp 0 "statically link to libstdc++ for LLVM"
opt rpath 0 "build rpaths into rustc itself"
+opt stage0-landing-pads 1 "enable landing pads during bootstrap with stage0"
# This is used by the automation to produce single-target nightlies
opt dist-host-only 0 "only install bins for the host architecture"
opt inject-std-version 1 "inject the current compiler version of libstd into programs"
probe CFG_GRUN grun
probe CFG_FLEX flex
probe CFG_BISON bison
-probe CFG_PANDOC pandoc
-probe CFG_XELATEX xelatex
probe CFG_GDB gdb
probe CFG_LLDB lldb
probe CFG_ADB adb
-if [ -n "$CFG_PANDOC" ]
-then
- # Extract "MAJOR MINOR" from Pandoc's version number
- PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc' |
- sed -E 's/pandoc(.exe)? ([0-9]+)\.([0-9]+).*/\2 \3/')
-
- MIN_PV_MAJOR="1"
- MIN_PV_MINOR="9"
-
- # these patterns are shell globs, *not* regexps
- PV_MAJOR=${PV_MAJOR_MINOR% *}
- PV_MINOR=${PV_MAJOR_MINOR#* }
-
- if [ "$PV_MAJOR" -lt "$MIN_PV_MAJOR" ] || [ "$PV_MINOR" -lt "$MIN_PV_MINOR" ]
- then
- step_msg "pandoc $PV_MAJOR.$PV_MINOR is too old. Need at least $MIN_PV_MAJOR.$MIN_PV_MINOR. Disabling"
- BAD_PANDOC=1
- fi
-fi
-
BIN_SUF=
if [ "$CFG_OSTYPE" = "pc-windows-gnu" ] || [ "$CFG_OSTYPE" = "pc-windows-msvc" ]
then
envopt CFLAGS
envopt CXXFLAGS
+# stdc++ name in use
+# used to manage non-standard name (on OpenBSD for example)
+program_transform_name=$($CFG_CC -v 2>&1 | sed -n "s/.*--program-transform-name='\([^']*\)'.*/\1/p")
+CFG_STDCPP_NAME=$(echo "stdc++" | sed "${program_transform_name}")
+putvar CFG_STDCPP_NAME
+
# a little post-processing of various config values
CFG_PREFIX=${CFG_PREFIX%/}
CFG_MANDIR=${CFG_MANDIR%/}
putvar CFG_MSVC_LIB_PATH_${bits}
;;
+ *-rumprun-netbsd)
+ step_msg "targeting rumprun-netbsd, disabling jemalloc"
+ CFG_DISABLE_JEMALLOC=1
+ putvar CFG_DISABLE_JEMALLOC
+ ;;
+
*)
;;
esac
fi
-if [ -n $BAD_PANDOC ]
-then
- CFG_PANDOC=
- putvar CFG_PANDOC
-fi
-
putvar CFG_LLVM_SRC_DIR
for t in $CFG_HOST
Specify the name of the crate being built.
.TP
\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info]
-Configure the output that \fBrustc\fR will produce.
+Configure the output that \fBrustc\fR will produce. Each option may also be of
+the form KIND=PATH to specify the explicit output location for that particular
+emission kind.
.TP
\fB\-\-print\fR [crate\-name|file\-names|sysroot]
Comma separated list of compiler information to print on stdout.
.TP
\fB\-o\fR \fIFILENAME\fR
Write output to \fIFILENAME\fR.
-Ignored if multiple \fI\-\-emit\fR outputs are specified.
+Ignored if multiple \fI\-\-emit\fR outputs are specified which don't have an
+explicit path otherwise.
.TP
\fB\-\-out\-dir\fR \fIDIR\fR
Write output to compiler\[hy]chosen filename in \fIDIR\fR.
CFG_STATIC_LIB_NAME_mips-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so
CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM
-CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS)
-CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 -mno-compact-eh $(CFLAGS)
+CFG_JEMALLOC_CFLAGS_mips-unknown-linux-gnu := -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
+CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 $(CFLAGS)
CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti $(CXXFLAGS)
CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32
CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list=
CFG_LDPATH_mips-unknown-linux-gnu :=
CFG_RUN_mips-unknown-linux-gnu=
CFG_RUN_TARG_mips-unknown-linux-gnu=
-RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2,+o32" -C soft-float
+RUSTC_FLAGS_mips-unknown-linux-gnu := -C target-cpu=mips32r2 -C target-feature="+mips32r2" -C soft-float
CFG_GNU_TRIPLE_mips-unknown-linux-gnu := mips-unknown-linux-gnu
# mipsel-unknown-linux-gnu configuration
-CC_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc
-CXX_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-g++
-CPP_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-gcc
-AR_mipsel-unknown-linux-gnu=mipsel-unknown-linux-gnu-ar
+CC_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc
+CXX_mipsel-unknown-linux-gnu=mipsel-linux-gnu-g++
+CPP_mipsel-unknown-linux-gnu=mipsel-linux-gnu-gcc
+AR_mipsel-unknown-linux-gnu=mipsel-linux-gnu-ar
CFG_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).so
CFG_STATIC_LIB_NAME_mipsel-unknown-linux-gnu=lib$(1).a
CFG_LIB_GLOB_mipsel-unknown-linux-gnu=lib$(1)-*.so
CFG_LDPATH_mipsel-unknown-linux-gnu :=
CFG_RUN_mipsel-unknown-linux-gnu=
CFG_RUN_TARG_mipsel-unknown-linux-gnu=
-RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32,+o32"
+RUSTC_FLAGS_mipsel-unknown-linux-gnu := -C target-cpu=mips32 -C target-feature="+mips32"
CFG_GNU_TRIPLE_mipsel-unknown-linux-gnu := mipsel-unknown-linux-gnu
--- /dev/null
+# x86_64-rumprun-netbsd configuration
+CROSS_PREFIX_x86_64-rumprun-netbsd=x86_64-rumprun-netbsd-
+CC_x86_64-rumprun-netbsd=gcc
+CXX_x86_64-rumprun-netbsd=g++
+CPP_x86_64-rumprun-netbsd=gcc -E
+AR_x86_64-rumprun-netbsd=ar
+CFG_INSTALL_ONLY_RLIB_x86_64-rumprun-netbsd = 1
+CFG_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).so
+CFG_STATIC_LIB_NAME_x86_64-rumprun-netbsd=lib$(1).a
+CFG_LIB_GLOB_x86_64-rumprun-netbsd=lib$(1)-*.so
+CFG_JEMALLOC_CFLAGS_x86_64-rumprun-netbsd := -m64
+CFG_GCCISH_CFLAGS_x86_64-rumprun-netbsd := -Wall -Werror -g -fPIC -m64
+CFG_GCCISH_CXXFLAGS_x86_64-rumprun-netbsd :=
+CFG_GCCISH_LINK_FLAGS_x86_64-rumprun-netbsd :=
+CFG_GCCISH_DEF_FLAG_x86_64-rumprun-netbsd :=
+CFG_LLC_FLAGS_x86_64-rumprun-netbsd :=
+CFG_INSTALL_NAME_x86_64-rumprun-netbsd =
+CFG_EXE_SUFFIX_x86_64-rumprun-netbsd =
+CFG_WINDOWSY_x86_64-rumprun-netbsd :=
+CFG_UNIXY_x86_64-rumprun-netbsd := 1
+CFG_LDPATH_x86_64-rumprun-netbsd :=
+CFG_RUN_x86_64-rumprun-netbsd=$(2)
+CFG_RUN_TARG_x86_64-rumprun-netbsd=$(call CFG_RUN_x86_64-rumprun-netbsd,,$(2))
+CFG_GNU_TRIPLE_x86_64-rumprun-netbsd := x86_64-rumprun-netbsd
# x86_64-unknown-netbsd configuration
+CROSS_PREFIX_x86_64-unknown-netbsd=x86_64-unknown-netbsd-
CC_x86_64-unknown-netbsd=$(CC)
CXX_x86_64-unknown-netbsd=$(CXX)
CPP_x86_64-unknown-netbsd=$(CPP)
TOOLS := compiletest rustdoc rustc rustbook error-index-generator
DEPS_core :=
+DEPS_alloc := core libc alloc_system
+DEPS_alloc_system := core libc
+DEPS_collections := core alloc rustc_unicode
DEPS_libc := core
+DEPS_rand := core
+DEPS_rustc_bitflags := core
DEPS_rustc_unicode := core
-DEPS_alloc := core libc alloc_system
+
DEPS_std := core libc rand alloc collections rustc_unicode \
native:rust_builtin native:backtrace \
alloc_system
+DEPS_arena := std
+DEPS_glob := std
+DEPS_flate := std native:miniz
+DEPS_fmt_macros = std
+DEPS_getopts := std
DEPS_graphviz := std
+DEPS_log := std
+DEPS_num := std
+DEPS_rbml := std log serialize
+DEPS_serialize := std log
+DEPS_term := std log
+DEPS_test := std getopts serialize rbml term native:rust_test_helpers
+
DEPS_syntax := std term serialize log fmt_macros arena libc rustc_bitflags
+
+DEPS_rustc := syntax flate arena serialize getopts rbml rustc_front\
+ log graphviz rustc_llvm rustc_back rustc_data_structures
+DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
+DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
+DEPS_rustc_data_structures := std log serialize
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
rustc_trans rustc_privacy rustc_lint rustc_front
-DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
- log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
-DEPS_rustc_mir := rustc rustc_front syntax
-DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
-DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
-DEPS_rustc_resolve := rustc rustc_front log syntax
-DEPS_rustc_privacy := rustc rustc_front log syntax
+DEPS_rustc_front := std syntax log serialize
DEPS_rustc_lint := rustc log syntax
-DEPS_rustc := syntax flate arena serialize getopts rbml \
- log graphviz rustc_llvm rustc_back rustc_data_structures
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
+DEPS_rustc_mir := rustc rustc_front syntax
+DEPS_rustc_resolve := rustc rustc_front log syntax
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
-DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
-DEPS_rustc_front := std syntax log serialize
-DEPS_rustc_data_structures := std log serialize
+DEPS_rustc_privacy := rustc rustc_front log syntax
+DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
+ log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
+DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
+
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
test rustc_lint rustc_front
-DEPS_rustc_bitflags := core
-DEPS_flate := std native:miniz
-DEPS_arena := std
-DEPS_graphviz := std
-DEPS_glob := std
-DEPS_serialize := std log
-DEPS_rbml := std log serialize
-DEPS_term := std log
-DEPS_getopts := std
-DEPS_collections := core alloc rustc_unicode
-DEPS_num := std
-DEPS_test := std getopts serialize rbml term native:rust_test_helpers
-DEPS_rand := core
-DEPS_log := std
-DEPS_fmt_macros = std
-DEPS_alloc_system := core libc
+
TOOL_DEPS_compiletest := test getopts
TOOL_DEPS_rustdoc := rustdoc
# * dist-docs - Stage docs for upload
PKG_NAME := $(CFG_PACKAGE_NAME)
+STD_PKG_NAME := rust-std-$(CFG_PACKAGE_VERS)
DOC_PKG_NAME := rust-docs-$(CFG_PACKAGE_VERS)
MINGW_PKG_NAME := rust-mingw-$(CFG_PACKAGE_VERS)
-C $(S) \
--exclude-vcs \
--exclude=*~ \
+ --exclude=*.pyc \
--exclude=*/llvm/test/*/*.ll \
--exclude=*/llvm/test/*/*.td \
--exclude=*/llvm/test/*/*.s \
# Unix binary installer tarballs
######################################################################
-define DEF_INSTALLER
+define DEF_START_INSTALLER
+dist-install-dir-$(1)-%: PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
+dist-install-dir-$(1)-%: PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
+dist-install-dir-$(1)-%: PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
+dist-install-dir-$(1)-%: PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
+dist-install-dir-$(1)-%: PREPARE_CLEAN=true
$$(eval $$(call DEF_PREPARE,dir-$(1)))
+endef
-dist-install-dir-$(1): PREPARE_HOST=$(1)
-dist-install-dir-$(1): PREPARE_TARGETS=$(2)
-dist-install-dir-$(1): PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image
-dist-install-dir-$(1): PREPARE_DIR_CMD=$(DEFAULT_PREPARE_DIR_CMD)
-dist-install-dir-$(1): PREPARE_BIN_CMD=$(DEFAULT_PREPARE_BIN_CMD)
-dist-install-dir-$(1): PREPARE_LIB_CMD=$(DEFAULT_PREPARE_LIB_CMD)
-dist-install-dir-$(1): PREPARE_MAN_CMD=$(DEFAULT_PREPARE_MAN_CMD)
-dist-install-dir-$(1): PREPARE_CLEAN=true
-dist-install-dir-$(1): prepare-base-dir-$(1) docs
+$(foreach target,$(CFG_TARGET),\
+ $(eval $(call DEF_START_INSTALLER,$(target))))
+
+define DEF_INSTALLER
+
+dist-install-dir-$(1)-host: PREPARE_HOST=$(1)
+dist-install-dir-$(1)-host: PREPARE_TARGETS=$(2)
+dist-install-dir-$(1)-host: PREPARE_DEST_DIR=tmp/dist/$$(PKG_NAME)-$(1)-image
+dist-install-dir-$(1)-host: prepare-base-dir-$(1)-host docs
$$(Q)mkdir -p $$(PREPARE_DEST_DIR)/share/doc/rust
$$(Q)$$(PREPARE_MAN_CMD) $$(S)COPYRIGHT $$(PREPARE_DEST_DIR)/share/doc/rust
$$(Q)$$(PREPARE_MAN_CMD) $$(S)LICENSE-APACHE $$(PREPARE_DEST_DIR)/share/doc/rust
# This tiny morsel of metadata is used by rust-packaging
$$(Q)echo "$(CFG_VERSION)" > tmp/dist/$$(PKG_NAME)-$(1)-overlay/version
-dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1) prepare-overlay-$(1)
+dist/$$(PKG_NAME)-$(1).tar.gz: dist-install-dir-$(1)-host prepare-overlay-$(1)
@$(call E, build: $$@)
-# Copy essential gcc components into installer
-ifdef CFG_WINDOWSY_$(1)
-ifeq ($$(findstring gnu,$(1)),gnu)
+# On a MinGW target we've got a few runtime DLL dependencies that we need
+# to include. THe first argument to `make-win-dist` is where to put these DLLs
+# (the image we're creating) and the second argument is a junk directory to
+# ignore all the other MinGW stuff the script creates.
+ifeq ($$(findstring pc-windows-gnu,$(1)),pc-windows-gnu)
$$(Q)rm -Rf tmp/dist/win-rust-gcc-$(1)
- $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py tmp/dist/$$(PKG_NAME)-$(1)-image tmp/dist/win-rust-gcc-$(1) $(1)
- $$(Q)cp -r $$(S)src/etc/third-party tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/
+ $$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \
+ tmp/dist/$$(PKG_NAME)-$(1)-image \
+ tmp/dist/win-rust-gcc-$(1) $(1)
+endif
+# On 32-bit MinGW we're always including a DLL which needs some extra licenses
+# to distribute. On 64-bit MinGW we don't actually distribute anything requiring
+# us to distribute a license but it's likely that the install will *also*
+# include the rust-mingw package down below, which also need licenses, so to be
+# safe we just inlude it here in all MinGW packages.
+ifdef CFG_WINDOWSY_$(1)
+ifeq ($$(findstring $(1),gnu),gnu)
+ $$(Q)cp -r $$(S)src/etc/third-party \
+ tmp/dist/$$(PKG_NAME)-$(1)-image/share/doc/
endif
endif
$$(Q)$$(S)src/rust-installer/gen-installer.sh \
--bulk-dirs=share/doc/rust/html
$$(Q)rm -R tmp/dist/$$(DOC_PKG_NAME)-$(1)-image
+# Creates the rust-mingw package, and the first argument to make-win-dist is a
+# "temporary directory" which is just thrown away (this contains the runtime
+# DLLs included in the rustc package above) and the second argument is where to
+# place all the MinGW components (which is what we want).
dist-mingw-install-dir-$(1):
$$(Q)mkdir -p tmp/dist/rust-mingw-tmp-$(1)-image
$$(Q)rm -Rf tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image
$$(Q)$$(CFG_PYTHON) $$(S)src/etc/make-win-dist.py \
- tmp/dist/rust-mingw-tmp-$(1)-image tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1)
+ tmp/dist/rust-mingw-tmp-$(1)-image \
+ tmp/dist/$$(MINGW_PKG_NAME)-$(1)-image $(1)
dist/$$(MINGW_PKG_NAME)-$(1).tar.gz: dist-mingw-install-dir-$(1)
@$(call E, build: $$@)
endef
-ifneq ($(CFG_ENABLE_DIST_HOST_ONLY),)
-$(foreach host,$(CFG_HOST),\
- $(eval $(call DEF_INSTALLER,$(host),$(host))))
-else
+# $(1) - host
+# $(2) - target
+define DEF_INSTALLER_TARGETS
+
+dist-install-dir-$(2)-target: PREPARE_HOST=$(1)
+dist-install-dir-$(2)-target: PREPARE_TARGETS=$(2)
+dist-install-dir-$(2)-target: PREPARE_DEST_DIR=tmp/dist/$$(STD_PKG_NAME)-$(2)-image
+dist-install-dir-$(2)-target: prepare-base-dir-$(2)-target
+
+dist/$$(STD_PKG_NAME)-$(2).tar.gz: dist-install-dir-$(2)-target
+ @$$(call E, build: $$@)
+ $$(Q)$$(S)src/rust-installer/gen-installer.sh \
+ --product-name=Rust \
+ --rel-manifest-dir=rustlib \
+ --success-message=std-is-standing-at-the-ready. \
+ --image-dir=tmp/dist/$$(STD_PKG_NAME)-$(2)-image \
+ --work-dir=tmp/dist \
+ --output-dir=dist \
+ --package-name=$$(STD_PKG_NAME)-$(2) \
+ --component-name=rust-std-$(2) \
+ --legacy-manifest-dirs=rustlib,cargo
+ $$(Q)rm -R tmp/dist/$$(STD_PKG_NAME)-$(2)-image
+endef
+
$(foreach host,$(CFG_HOST),\
- $(eval $(call DEF_INSTALLER,$(host),$(CFG_TARGET))))
-endif
+ $(eval $(call DEF_INSTALLER,$(host))))
-dist-install-dirs: $(foreach host,$(CFG_HOST),dist-install-dir-$(host))
+# When generating packages for the standard library, we've actually got a lot of
+# artifacts to choose from. Each of the CFG_HOST compilers will have a copy of
+# the standard library for each CFG_TARGET, but we only want to generate one
+# standard library package. As a result, for each entry in CFG_TARGET we need to
+# pick a CFG_HOST to get the standard library from.
+#
+# In theory it doesn't actually matter what host we choose as it should be the
+# case that all hosts produce the same set of libraries for a target (regardless
+# of the host itself). Currently there is a bug in the compiler, however, which
+# means this is not the case (see #29228 and #29235). To solve the first of
+# those bugs, we prefer to select a standard library from the host it was
+# generated from, allowing plugins to work in more situations.
+#
+# For all CFG_TARGET entries in CFG_HOST, however, we just pick CFG_BUILD as the
+# host we slurp up a standard library from.
+$(foreach host,$(CFG_HOST),\
+ $(eval $(call DEF_INSTALLER_TARGETS,$(host),$(host))))
+$(foreach target,$(filter-out $(CFG_HOST),$(CFG_TARGET)),\
+ $(eval $(call DEF_INSTALLER_TARGETS,$(CFG_BUILD),$(target))))
ifdef CFG_WINDOWSY_$(CFG_BUILD)
define BUILD_MINGW_TARBALL
MAYBE_DOC_TARBALLS=$(foreach host,$(CFG_HOST),dist/$(DOC_PKG_NAME)-$(host).tar.gz)
endif
-dist-tar-bins: $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \
+dist-tar-bins: \
+ $(foreach host,$(CFG_HOST),dist/$(PKG_NAME)-$(host).tar.gz) \
+ $(foreach target,$(CFG_TARGET),dist/$(STD_PKG_NAME)-$(target).tar.gz) \
$(MAYBE_DOC_TARBALLS) $(MAYBE_MINGW_TARBALLS)
# Just try to run the compiler for the build host
$(Q)$(SG)check.sh $(S) "$(BG)" \
"$(CFG_GRUN)" "$(BG)verify" "$(BG)RustLexer.tokens"
else
-$(info cfg: grun not available, skipping lexer test...)
+$(info cfg: lexer tooling not available, skipping lexer test...)
check-lexer:
endif
else
-$(info cfg: antlr4 not available, skipping lexer test...)
+$(info cfg: lexer tooling not available, skipping lexer test...)
check-lexer:
endif
else
-$(info cfg: javac not available, skipping lexer test...)
+$(info cfg: lexer tooling not available, skipping lexer test...)
check-lexer:
endif
# option. This file may not be copied, modified, or distributed
# except according to those terms.
+RUN_INSALLER = cd tmp/empty_dir && \
+ sh ../../tmp/dist/$(1)/install.sh \
+ --prefix="$(DESTDIR)$(CFG_PREFIX)" \
+ --libdir="$(DESTDIR)$(CFG_LIBDIR)" \
+ --mandir="$(DESTDIR)$(CFG_MANDIR)"
+
install:
ifeq (root user, $(USER) $(patsubst %,user,$(SUDO_USER)))
# Build the dist as the original user
$(Q)$(MAKE) prepare_install
endif
ifeq ($(CFG_DISABLE_DOCS),)
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --disable-ldconfig
endif
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(foreach target,$(CFG_TARGET),\
+ ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --disable-ldconfig);)
+ $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD))
# Remove tmp files because it's a decent amount of disk space
$(Q)rm -R tmp/dist
$(Q)$(MAKE) prepare_uninstall
endif
ifeq ($(CFG_DISABLE_DOCS),)
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(DOC_PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(call RUN_INSALLER,$(DOC_PKG_NAME)-$(CFG_BUILD)) --uninstall
endif
- $(Q)cd tmp/empty_dir && sh ../../tmp/dist/$(PKG_NAME)-$(CFG_BUILD)/install.sh --uninstall --prefix="$(DESTDIR)$(CFG_PREFIX)" --libdir="$(DESTDIR)$(CFG_LIBDIR)" --mandir="$(DESTDIR)$(CFG_MANDIR)"
+ $(Q)$(call RUN_INSALLER,$(PKG_NAME)-$(CFG_BUILD)) --uninstall
+ $(Q)$(foreach target,$(CFG_TARGET),\
+ ($(call RUN_INSALLER,$(STD_PKG_NAME)-$(target)) --uninstall);)
# Remove tmp files because it's a decent amount of disk space
$(Q)rm -R tmp/dist
ifeq ($$(CFG_ENABLE_LLVM_STATIC_STDCPP),1)
LLVM_STDCPP_RUSTFLAGS_$(1) = -L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
- -print-file-name=libstdc++.a))"
+ -print-file-name=lib$(CFG_STDCPP_NAME).a))"
else
LLVM_STDCPP_RUSTFLAGS_$(1) =
endif
LLVM_LINKAGE_PATH_$(1):=$$(abspath $$(RT_OUTPUT_DIR_$(1))/llvmdeps.rs)
$$(LLVM_LINKAGE_PATH_$(1)): $(S)src/etc/mklldeps.py $$(LLVM_CONFIG_$(1))
$(Q)$(CFG_PYTHON) "$$<" "$$@" "$$(LLVM_COMPONENTS)" "$$(CFG_ENABLE_LLVM_STATIC_STDCPP)" \
- $$(LLVM_CONFIG_$(1))
+ $$(LLVM_CONFIG_$(1)) "$(CFG_STDCPP_NAME)"
endef
$(foreach host,$(CFG_HOST), \
######################################################################
# The version number
-CFG_RELEASE_NUM=1.4.0
+CFG_RELEASE_NUM=1.5.0
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
# NB Make sure it starts with a dot to conform to semver pre-release
# versions (section 9)
-CFG_PRERELEASE_VERSION=.4
+CFG_PRERELEASE_VERSION=.5
# Append a version-dependent hash to each library, so we can install different
# versions in the same place
ifdef CFG_ENABLE_DEBUGINFO
$(info cfg: enabling debuginfo (CFG_ENABLE_DEBUGINFO))
- CFG_RUSTC_FLAGS += -g
+ # FIXME: Re-enable -g in stage0 after new snapshot
+ #CFG_RUSTC_FLAGS += -g
+ RUSTFLAGS_STAGE1 += -g
+ RUSTFLAGS_STAGE2 += -g
+ RUSTFLAGS_STAGE3 += -g
endif
ifdef SAVE_TEMPS
# Landing pads require a lot of codegen. We can get through bootstrapping faster
# by not emitting them.
-RUSTFLAGS_STAGE0 += -Z no-landing-pads
-
-# Enable MIR to "always build" for crates where this works. This is
-# just temporary while MIR is being actively built up -- it's just a
-# poor man's unit testing infrastructure. Anyway we only want this for
-# stage1/stage2.
-define ADD_MIR_FLAG
-RUSTFLAGS1_$(1) += -Z always-build-mir
-RUSTFLAGS2_$(1) += -Z always-build-mir
-endef
-$(foreach crate,$(TARGET_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
-$(foreach crate,$(RUSTC_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
-$(foreach crate,$(HOST_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
+
+ifdef CFG_DISABLE_STAGE0_LANDING_PADS
+ RUSTFLAGS_STAGE0 += -Z no-landing-pads
+endif
# platform-specific auto-configuration
include $(CFG_SRC_DIR)mk/platform.mk
ifeq ($$(findstring $(HOST_$(1)),arm aarch64 mips mipsel powerpc),)
+ # On OpenBSD, we need to pass the path of libstdc++.so to the linker
+ # (use path of libstdc++.a which is a known name for the same path)
+ ifeq ($(OSTYPE_$(1)),unknown-openbsd)
+ RUSTC_FLAGS_$(1)=-L "$$(dir $$(shell $$(CC_$(1)) $$(CFG_GCCISH_CFLAGS_$(1)) \
+ -print-file-name=lib$(CFG_STDCPP_NAME).a))" \
+ $(RUSTC_FLAGS_$(1))
+ endif
+
# On Bitrig, we need the relocation model to be PIC for everything
ifeq (,$(filter $(OSTYPE_$(1)),bitrig))
LLVM_MC_RELOCATION_MODEL="pic"
define DEF_PREPARE
-prepare-base-$(1): PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE)
-prepare-base-$(1): PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin
-prepare-base-$(1): PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE)
-prepare-base-$(1): PREPARE_SOURCE_MAN_DIR=$$(S)/man
-prepare-base-$(1): PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin
-prepare-base-$(1): PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)
-prepare-base-$(1): PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1
-prepare-base-$(1): prepare-everything-$(1)
+prepare-base-$(1)-%: PREPARE_SOURCE_DIR=$$(PREPARE_HOST)/stage$$(PREPARE_STAGE)
+prepare-base-$(1)-%: PREPARE_SOURCE_BIN_DIR=$$(PREPARE_SOURCE_DIR)/bin
+prepare-base-$(1)-%: PREPARE_SOURCE_LIB_DIR=$$(PREPARE_SOURCE_DIR)/$$(CFG_LIBDIR_RELATIVE)
+prepare-base-$(1)-%: PREPARE_SOURCE_MAN_DIR=$$(S)/man
+prepare-base-$(1)-%: PREPARE_DEST_BIN_DIR=$$(PREPARE_DEST_DIR)/bin
+prepare-base-$(1)-%: PREPARE_DEST_LIB_DIR=$$(PREPARE_DEST_DIR)/$$(CFG_LIBDIR_RELATIVE)
+prepare-base-$(1)-%: PREPARE_DEST_MAN_DIR=$$(PREPARE_DEST_DIR)/share/man/man1
-prepare-everything-$(1): prepare-host-$(1) prepare-targets-$(1) prepare-debugger-scripts-$(1)
+prepare-base-$(1)-target: prepare-target-$(1)
+prepare-base-$(1)-host: prepare-host-$(1) prepare-debugger-scripts-$(1)
prepare-host-$(1): prepare-host-tools-$(1)
$$(foreach host,$$(CFG_HOST), \
$$(eval $$(call DEF_PREPARE_HOST_LIB,$$(lib),$$(PREPARE_STAGE),$$(host),$(1)))))
-prepare-targets-$(1): \
+prepare-target-$(1): \
$$(foreach host,$$(CFG_HOST), \
$$(foreach target,$$(CFG_TARGET), \
prepare-target-$$(target)-host-$$(host)-$$(PREPARE_STAGE)-$(1)))
$$(RMAKE_TESTS:%=$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok)
@touch $$@
+$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
+ export INCLUDE := $$(CFG_MSVC_INCLUDE_PATH_$$(HOST_$(3)))
+$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
+ export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(3)))
$(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
$(S)src/test/run-make/%/Makefile \
$$(CSREQ$(1)_T_$(2)_H_$(3))
$$(MAKE) \
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
$(3)/test/run-make/$$* \
- $$(CC_$(3)) \
+ '$$(CC_$(3))' \
"$$(CFG_GCCISH_CFLAGS_$(3))" \
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
"$$(TESTNAME)" \
"$$(LD_LIBRARY_PATH_ENV_HOSTDIR$(1)_T_$(2)_H_$(3))" \
"$$(LD_LIBRARY_PATH_ENV_TARGETDIR$(1)_T_$(2)_H_$(3))" \
$(1) \
- $$(S)
+ $$(S) \
+ $(3)
@touch -r $$@.start_time $$@ && rm $$@.start_time
else
# FIXME #11094 - The above rule doesn't work right for multiple targets
#![feature(box_syntax)]
#![feature(dynamic_lib)]
#![feature(libc)]
-#![feature(path_ext)]
#![feature(rustc_private)]
-#![feature(slice_splits)]
#![feature(str_char)]
#![feature(test)]
#![feature(vec_push_all)]
optflag("h", "help", "show this message"));
let (argv0, args_) = args.split_first().unwrap();
- if args[1] == "-h" || args[1] == "--help" {
+ if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0);
println!("{}", getopts::usage(&message, &groups));
println!("");
if !full_version_line.trim().is_empty() => {
let full_version_line = full_version_line.trim();
- // used to be a regex "(^|[^0-9])([0-9]\.[0-9])([^0-9]|$)"
+ // used to be a regex "(^|[^0-9])([0-9]\.[0-9]+)"
for (pos, c) in full_version_line.char_indices() {
if !c.is_digit(10) { continue }
if pos + 2 >= full_version_line.len() { continue }
if pos > 0 && full_version_line.char_at_reverse(pos).is_digit(10) {
continue
}
- if pos + 3 < full_version_line.len() &&
- full_version_line.char_at(pos + 3).is_digit(10) {
- continue
+ let mut end = pos + 3;
+ while end < full_version_line.len() &&
+ full_version_line.char_at(end).is_digit(10) {
+ end += 1;
}
- return Some(full_version_line[pos..pos+3].to_owned());
+ return Some(full_version_line[pos..end].to_owned());
}
println!("Could not extract GDB version from line '{}'",
full_version_line);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(deprecated)]
+
use std::dynamic_lib::DynamicLibrary;
use std::io::prelude::*;
use std::path::PathBuf;
// FIXME (#9639): This needs to handle non-utf8 paths
let mut link_args = vec!("-L".to_owned(),
aux_dir.to_str().unwrap().to_owned());
- let llvm_args = vec!("--emit=llvm-ir".to_owned(),
- "--crate-type=lib".to_owned());
+ let llvm_args = vec!("--emit=llvm-ir".to_owned(),);
link_args.extend(llvm_args);
let args = make_compile_args(config,
props,
## Building
-To generate all the docs, just run `make docs` from the root of the repository.
-This will convert the distributed Markdown docs to HTML and generate HTML doc
-for the 'std' and 'extra' libraries.
+To generate all the docs, follow the "Building Documentation" instructions in
+the README in the root of the repository. This will convert the distributed
+Markdown docs to HTML and generate HTML doc for the books, 'std' and 'extra'
+libraries.
To generate HTML documentation from one source file/crate, do something like:
## Why aren't modules type-parametric?
-We want to maintain the option to parametrize at runtime. We may eventually change this limitation, but initially this is how type parameters were implemented.
+We want to maintain the option to parameterize at runtime. We may eventually change this limitation, but initially this is how type parameters were implemented.
## Why aren't values type-parametric? Why only items?
# Is any part of this thing production-ready?
-No. Feel free to play around, but don't expect completeness or stability yet. Expect incompleteness and breakage.
+Yes!
# Is this a completely Mozilla-planned and orchestrated thing?
This document does not serve as an introduction to the language. Background
familiarity with the language is assumed. A separate [guide] is available to
-help acquire such background familiarity.
+help acquire such background.
This document also does not serve as a reference to the [standard] library
included in the language distribution. Those libraries are documented
| ',' | ';' ;
```
-Symbols are a general class of printable [token](#tokens) that play structural
-roles in a variety of grammar productions. They are catalogued here for
+Symbols are a general class of printable [tokens](#tokens) that play structural
+roles in a variety of grammar productions. They are cataloged here for
completeness as the set of remaining miscellaneous printable tokens that do not
otherwise appear as [unary operators](#unary-operator-expressions), [binary
operators](#binary-operator-expressions), or [keywords](#keywords).
## Statements
```antlr
-stmt : decl_stmt | expr_stmt ;
+stmt : decl_stmt | expr_stmt | ';' ;
```
### Declaration statements
## Type kinds
-**FIXME:** this this probably not relevant to the grammar...
+**FIXME:** this is probably not relevant to the grammar...
# Memory and concurrency models
- [Korean](https://github.com/rust-kr/doc.rust-kr.org)
- [Chinese](https://github.com/KaiserY/rust-book-chinese)
- [Spanish](https://goyox86.github.io/elpr)
+- [German](https://panicbit.github.io/rustbook-de)
% Atomics
Rust pretty blatantly just inherits C11's memory model for atomics. This is not
-due this model being particularly excellent or easy to understand. Indeed, this
-model is quite complex and known to have [several flaws][C11-busted]. Rather, it
-is a pragmatic concession to the fact that *everyone* is pretty bad at modeling
-atomics. At very least, we can benefit from existing tooling and research around
-C.
+due to this model being particularly excellent or easy to understand. Indeed,
+this model is quite complex and known to have [several flaws][C11-busted].
+Rather, it is a pragmatic concession to the fact that *everyone* is pretty bad
+at modeling atomics. At very least, we can benefit from existing tooling and
+research around C.
Trying to fully explain the model in this book is fairly hopeless. It's defined
in terms of madness-inducing causality graphs that require a full book to
* zero-extend if the source is unsigned
* sign-extend if the source is signed
* casting from a float to an integer will round the float towards zero
- * **[NOTE: currently this will cause Undefined Behaviour if the rounded
+ * **[NOTE: currently this will cause Undefined Behavior if the rounded
value cannot be represented by the target integer type][float-int]**.
This includes Inf and NaN. This is a bug and will be fixed.
* casting from an integer to float will produce the floating point
* casting from an f32 to an f64 is perfect and lossless
* casting from an f64 to an f32 will produce the closest possible value
(rounding strategy unspecified)
- * **[NOTE: currently this will cause Undefined Behaviour if the value
+ * **[NOTE: currently this will cause Undefined Behavior if the value
is finite but larger or smaller than the largest or smallest finite
value representable by f32][float-float]**. This is a bug and will
be fixed.
-% Concurrency and Paralellism
+% Concurrency and Parallelism
Rust as a language doesn't *really* have an opinion on how to do concurrency or
parallelism. The standard library exposes OS threads and blocking sys-calls
dropped other than dropping its children, then it means `Drop` doesn't need to
be implemented at all!
-**There is no stable way to prevent this behaviour in Rust 1.0.**
+**There is no stable way to prevent this behavior in Rust 1.0.**
Note that taking `&mut self` means that even if you could suppress recursive
Drop, Rust will prevent you from e.g. moving fields out of self. For most types,
and this works fine because when Rust goes to drop the `ptr` field it just sees
a [Unique] that has no actual `Drop` implementation. Similarly nothing can
-use-after-free the `ptr` because when drop exits, it becomes inacessible.
+use-after-free the `ptr` because when drop exits, it becomes inaccessible.
However this wouldn't work:
happily proceed to tell the box to Drop itself and everything will blow up with
use-after-frees and double-frees.
-Note that the recursive drop behaviour applies to all structs and enums
+Note that the recursive drop behavior applies to all structs and enums
regardless of whether they implement Drop. Therefore something like
```rust
// x goes out of scope; x was uninit; do nothing.
```
-Similarly, branched code where all branches have the same behaviour with respect
+Similarly, branched code where all branches have the same behavior with respect
to initialization has static drop semantics:
```rust
when we talked about `'a: 'b`, it was ok for `'a` to live *exactly* as long as
`'b`. At first glance, this seems to be a meaningless distinction. Nothing ever
gets dropped at the same time as another, right? This is why we used the
-following desugarring of `let` statements:
+following desugaring of `let` statements:
```rust,ignore
let x;
**For a generic type to soundly implement drop, its generics arguments must
strictly outlive it.**
-This rule is sufficient but not necessary to satisfy the drop checker. That is,
-if your type obeys this rule then it's definitely sound to drop. However
-there are special cases where you can fail to satisfy this, but still
-successfully pass the borrow checker. These are the precise rules that are
-currently up in the air.
+Obeying this rule is (usually) necessary to satisfy the borrow
+checker; obeying it is sufficient but not necessary to be
+sound. That is, if your type obeys this rule then it's definitely
+sound to drop.
+
+The reason that it is not always necessary to satisfy the above rule
+is that some Drop implementations will not access borrowed data even
+though their type gives them the capability for such access.
+
+For example, this variant of the above `Inspector` example will never
+accessed borrowed data:
+
+```rust,ignore
+struct Inspector<'a>(&'a u8, &'static str);
+
+impl<'a> Drop for Inspector<'a> {
+ fn drop(&mut self) {
+ println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
+ }
+}
+
+fn main() {
+ let (inspector, days);
+ days = Box::new(1);
+ inspector = Inspector(&days, "gadget");
+ // Let's say `days` happens to get dropped first.
+ // Even when Inspector is dropped, its destructor will not access the
+ // borrowed `days`.
+}
+```
+
+Likewise, this variant will also never access borrowed data:
+
+```rust,ignore
+use std::fmt;
+
+struct Inspector<T: fmt::Display>(T, &'static str);
+
+impl<T: fmt::Display> Drop for Inspector<T> {
+ fn drop(&mut self) {
+ println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
+ }
+}
+
+fn main() {
+ let (inspector, days): (Inspector<&u8>, Box<u8>);
+ days = Box::new(1);
+ inspector = Inspector(&days, "gadget");
+ // Let's say `days` happens to get dropped first.
+ // Even when Inspector is dropped, its destructor will not access the
+ // borrowed `days`.
+}
+```
+
+However, *both* of the above variants are rejected by the borrow
+checker during the analysis of `fn main`, saying that `days` does not
+live long enough.
+
+The reason is that the borrow checking analysis of `main` does not
+know about the internals of each Inspector's Drop implementation. As
+far as the borrow checker knows while it is analyzing `main`, the body
+of an inspector's destructor might access that borrowed data.
+
+Therefore, the drop checker forces all borrowed data in a value to
+strictly outlive that value.
+
+# An Escape Hatch
+
+The precise rules that govern drop checking may be less restrictive in
+the future.
+
+The current analysis is deliberately conservative and trivial; it forces all
+borrowed data in a value to outlive that value, which is certainly sound.
+
+Future versions of the language may make the analysis more precise, to
+reduce the number of cases where sound code is rejected as unsafe.
+This would help address cases such as the two Inspectors above that
+know not to inspect during destruction.
+
+In the meantime, there is an unstable attribute that one can use to
+assert (unsafely) that a generic type's destructor is *guaranteed* to
+not access any expired data, even if its type gives it the capability
+to do so.
+
+That attribute is called `unsafe_destructor_blind_to_params`.
+To deploy it on the Inspector example from above, we would write:
+
+```rust,ignore
+struct Inspector<'a>(&'a u8, &'static str);
+
+impl<'a> Drop for Inspector<'a> {
+ #[unsafe_destructor_blind_to_params]
+ fn drop(&mut self) {
+ println!("Inspector(_, {}) knows when *not* to inspect.", self.1);
+ }
+}
+```
+
+This attribute has the word `unsafe` in it because the compiler is not
+checking the implicit assertion that no potentially expired data
+(e.g. `self.0` above) is accessed.
+
+It is sometimes obvious that no such access can occur, like the case above.
+However, when dealing with a generic type parameter, such access can
+occur indirectly. Examples of such indirect access are:
+
+ * invoking a callback,
+ * via a trait method call.
+
+(Future changes to the language, such as impl specialization, may add
+other avenues for such indirect access.)
+
+Here is an example of invoking a callback:
+
+```rust,ignore
+struct Inspector<T>(T, &'static str, Box<for <'r> fn(&'r T) -> String>);
+
+impl<T> Drop for Inspector<T> {
+ fn drop(&mut self) {
+ // The `self.2` call could access a borrow e.g. if `T` is `&'a _`.
+ println!("Inspector({}, {}) unwittingly inspects expired data.",
+ (self.2)(&self.0), self.1);
+ }
+}
+```
+
+Here is an example of a trait method call:
+
+```rust,ignore
+use std::fmt;
+
+struct Inspector<T: fmt::Display>(T, &'static str);
+
+impl<T: fmt::Display> Drop for Inspector<T> {
+ fn drop(&mut self) {
+ // There is a hidden call to `<T as Display>::fmt` below, which
+ // could access a borrow e.g. if `T` is `&'a _`
+ println!("Inspector({}, {}) unwittingly inspects expired data.",
+ self.0, self.1);
+ }
+}
+```
+
+And of course, all of these accesses could be further hidden within
+some other method invoked by the destructor, rather than being written
+directly within it.
+
+In all of the above cases where the `&'a u8` is accessed in the
+destructor, adding the `#[unsafe_destructor_blind_to_params]`
+attribute makes the type vulnerable to misuse that the borrower
+checker will not catch, inviting havoc. It is better to avoid adding
+the attribute.
+
+# Is that all about drop checker?
It turns out that when writing unsafe code, we generally don't need to
worry at all about doing the right thing for the drop checker. However there
is one special case that you need to worry about, which we will look at in
the next section.
+
There are two major DSTs exposed by the language: trait objects, and slices.
A trait object represents some type that implements the traits it specifies.
-The exact original type is *erased* in favour of runtime reflection
+The exact original type is *erased* in favor of runtime reflection
with a vtable containing all the information necessary to use the type.
This is the information that completes a trait object: a pointer to its vtable.
the ability to be confident that certain situations are statically impossible.
One final subtle detail about empty types is that raw pointers to them are
-actually valid to construct, but dereferencing them is Undefined Behaviour
+actually valid to construct, but dereferencing them is Undefined Behavior
because that doesn't actually make sense. That is, you could model C's `void *`
type with `*const Void`, but this doesn't necessarily gain anything over using
e.g. `*const ()`, which *is* safe to randomly dereference.
println!("{}", vec[0]);
```
-This is pretty clearly Not Good. Unfortunately, we're kind've stuck between a
+This is pretty clearly Not Good. Unfortunately, we're kind of stuck between a
rock and a hard place: maintaining consistent state at every step has an
enormous cost (and would negate any benefits of the API). Failing to maintain
-consistent state gives us Undefined Behaviour in safe code (making the API
+consistent state gives us Undefined Behavior in safe code (making the API
unsound).
So what can we do? Well, we can pick a trivially consistent state: set the Vec's
len to be 0 when we start the iteration, and fix it up if necessary in the
destructor. That way, if everything executes like normal we get the desired
-behaviour with minimal overhead. But if someone has the *audacity* to
+behavior with minimal overhead. But if someone has the *audacity* to
mem::forget us in the middle of the iteration, all that does is *leak even more*
(and possibly leave the Vec in an unexpected but otherwise consistent state).
Since we've accepted that mem::forget is safe, this is definitely safe. We call
fn new(data: T) -> Self {
unsafe {
// Wouldn't it be nice if heap::allocate worked like this?
- let ptr = heap::allocate<RcBox<T>>();
+ let ptr = heap::allocate::<RcBox<T>>();
ptr::write(ptr, RcBox {
data: data,
ref_count: 1,
```
Dang. Here the destructor running was pretty fundamental to the API, and it had
-to be scrapped in favour of a completely different design.
+to be scrapped in favor of a completely different design.
-[ex2]: lifetimes.html#example-2:-aliasing-a-mutable-reference
+[ex2]: lifetimes.html#example-aliasing-a-mutable-reference
The problem here is is bit more subtle and interesting. We want Rust to
reject this program for the following reason: We have a live shared reference `x`
-to a descendent of `data` when we try to take a mutable reference to `data`
+to a descendant of `data` when we try to take a mutable reference to `data`
to `push`. This would create an aliased mutable reference, which would
violate the *second* rule of references.
Safe Rust is the *true* Rust programming language. If all you do is write Safe
Rust, you will never have to worry about type-safety or memory-safety. You will
-never endure a null or dangling pointer, or any of that Undefined Behaviour
+never endure a null or dangling pointer, or any of that Undefined Behavior
nonsense.
*That's totally awesome.*
* Mutate statics
That's it. The reason these operations are relegated to Unsafe is that misusing
-any of these things will cause the ever dreaded Undefined Behaviour. Invoking
-Undefined Behaviour gives the compiler full rights to do arbitrarily bad things
-to your program. You definitely *should not* invoke Undefined Behaviour.
+any of these things will cause the ever dreaded Undefined Behavior. Invoking
+Undefined Behavior gives the compiler full rights to do arbitrarily bad things
+to your program. You definitely *should not* invoke Undefined Behavior.
-Unlike C, Undefined Behaviour is pretty limited in scope in Rust. All the core
+Unlike C, Undefined Behavior is pretty limited in scope in Rust. All the core
language cares about is preventing the following things:
* Dereferencing null or dangling pointers
* Unwinding into another language
* Causing a [data race][race]
-That's it. That's all the causes of Undefined Behaviour baked into Rust. Of
+That's it. That's all the causes of Undefined Behavior baked into Rust. Of
course, unsafe functions and traits are free to declare arbitrary other
-constraints that a program must maintain to avoid Undefined Behaviour. However,
+constraints that a program must maintain to avoid Undefined Behavior. However,
generally violations of these constraints will just transitively lead to one of
the above problems. Some additional constraints may also derive from compiler
intrinsics that make special assumptions about how code can be optimized.
`repr(C)` can be applied to types that will be nonsensical or problematic if
passed through the FFI boundary.
-* ZSTs are still zero-sized, even though this is not a standard behaviour in
-C, and is explicitly contrary to the behaviour of an empty type in C++, which
+* ZSTs are still zero-sized, even though this is not a standard behavior in
+C, and is explicitly contrary to the behavior of an empty type in C++, which
still consumes a byte of space.
* DSTs, tuples, and tagged unions are not a concept in C and as such are never
However if you take a reference to a packed field, it's unlikely that the
compiler will be able to emit code to avoid an unaligned load.
-**[As of Rust 1.0 this can cause undefined behaviour.][ub loads]**
+**[As of Rust 1.0 this can cause undefined behavior.][ub loads]**
`repr(packed)` is not to be used lightly. Unless you have extreme requirements,
this should not be used.
a reference into it. This is why Rust requires any references to freeze the
referent and its owners.
-
* one of them is a write
* one of them is unsynchronized
-A data race has Undefined Behaviour, and is therefore impossible to perform
+A data race has Undefined Behavior, and is therefore impossible to perform
in Safe Rust. Data races are *mostly* prevented through rust's ownership system:
it's impossible to alias a mutable reference, so it's impossible to perform a
data race. Interior mutability makes this more complicated, which is largely why
// bounds checked, and there's no chance of the value getting changed
// in the middle. However our program may panic if the thread we spawned
// managed to increment before this ran. A race condition because correct
-// program execution (panicing is rarely correct) depends on order of
+// program execution (panicking is rarely correct) depends on order of
// thread execution.
println!("{}", data[idx.load(Ordering::SeqCst)]);
```
`n`. So alignment 2 means you must be stored at an even address, and 1 means
that you can be stored anywhere. Alignment is at least 1, and always a power of
2. Most primitives are generally aligned to their size, although this is
-platform-specific behaviour. In particular, on x86 `u64` and `f64` may be only
+platform-specific behavior. In particular, on x86 `u64` and `f64` may be only
aligned to 32 bits.
A type's size must always be a multiple of its alignment. This ensures that an
special constrained representations. As such it is *especially* desirable that
we leave enum layout unspecified today.
-[dst]: exotic-sizes.html#dynamically-sized-types-(dsts)
+[dst]: exotic-sizes.html#dynamically-sized-types-dsts
* `slice::get_unchecked` will perform unchecked indexing, allowing memory
safety to be freely violated.
-* `ptr::offset` is an intrinsic that invokes Undefined Behaviour if it is
- not "in bounds" as defined by LLVM.
+* every raw pointer to sized type has intrinsic `offset` method that invokes
+ Undefined Behavior if it is not "in bounds" as defined by LLVM.
* `mem::transmute` reinterprets some value as having the given type,
bypassing type safety in arbitrary ways. (see [conversions] for details)
* All FFI functions are `unsafe` because they can do arbitrary things.
The need for unsafe traits boils down to the fundamental property of safe code:
**No matter how completely awful Safe code is, it can't cause Undefined
-Behaviour.**
+Behavior.**
-This means that Unsafe Rust, **the royal vanguard of Undefined Behaviour**, has to be
+This means that Unsafe Rust, **the royal vanguard of Undefined Behavior**, has to be
*super paranoid* about generic safe code. To be clear, Unsafe Rust is totally free to trust
specific safe code. Anything else would degenerate into infinite spirals of
paranoid despair. In particular it's generally regarded as ok to trust the standard library
implemented. Since they're *marker traits* (they have no associated items like
methods), correctly implemented simply means that they have the intrinsic
properties an implementor should have. Incorrectly implementing Send or Sync can
-cause Undefined Behaviour.
+cause Undefined Behavior.
Send and Sync are also automatically derived traits. This means that, unlike
every other trait, if a type is composed entirely of Send or Sync types, then it
`mem::transmute<T, U>` takes a value of type `T` and reinterprets it to have
type `U`. The only restriction is that the `T` and `U` are verified to have the
-same size. The ways to cause Undefined Behaviour with this are mind boggling.
+same size. The ways to cause Undefined Behavior with this are mind boggling.
* First and foremost, creating an instance of *any* type with an invalid state
is going to cause arbitrary chaos that can't really be predicted.
`mem::transmute_copy<T, U>` somehow manages to be *even more* wildly unsafe than
this. It copies `size_of<U>` bytes out of an `&T` and interprets them as a `U`.
The size check that `mem::transmute` has is gone (as it may be valid to copy
-out a prefix), though it is Undefined Behaviour for `U` to be larger than `T`.
+out a prefix), though it is Undefined Behavior for `U` to be larger than `T`.
Also of course you can get most of the functionality of these functions using
pointer casts.
Unsafe code can often end up producing references or lifetimes out of thin air.
Such lifetimes come into the world as *unbounded*. The most common source of this
-is derefencing a raw pointer, which produces a reference with an unbounded lifetime.
+is dereferencing a raw pointer, which produces a reference with an unbounded lifetime.
Such a lifetime becomes as big as context demands. This is in fact more powerful
than simply becoming `'static`, because for instance `&'static &'a T`
will fail to typecheck, but the unbound lifetime will perfectly mold into
lifetime can be regarded as `'static`.
Almost no reference is `'static`, so this is probably wrong. `transmute` and
-`transmute_copy` are the two other primary offenders. One should endeavour to
+`transmute_copy` are the two other primary offenders. One should endeavor to
bound an unbounded lifetime as quick as possible, especially across function
boundaries.
(this is equivalent to memcpy -- note that the argument order is reversed!)
It should go without saying that these functions, if misused, will cause serious
-havoc or just straight up Undefined Behaviour. The only things that these
+havoc or just straight up Undefined Behavior. The only things that these
functions *themselves* require is that the locations you want to read and write
are allocated. However the ways writing arbitrary bits to arbitrary
locations of memory can break things are basically uncountable!
*uninitialized*. In this state the value of the memory is an indeterminate pile
of bits that may or may not even reflect a valid state for the type that is
supposed to inhabit that location of memory. Attempting to interpret this memory
-as a value of *any* type will cause Undefined Behaviour. Do Not Do This.
+as a value of *any* type will cause Undefined Behavior. Do Not Do This.
Rust provides mechanisms to work with uninitialized memory in checked (safe) and
-unchecked (unsafe) ways.
\ No newline at end of file
+unchecked (unsafe) ways.
Rust's unwinding strategy is not specified to be fundamentally compatible
with any other language's unwinding. As such, unwinding into Rust from another
-language, or unwinding into another language from Rust is Undefined Behaviour.
+language, or unwinding into another language from Rust is Undefined Behavior.
You must *absolutely* catch any panics at the FFI boundary! What you do at that
point is up to you, but *something* must be done. If you fail to do this,
at best, your application will crash and burn. At worst, your application *won't*
If you don't care about the null-pointer optimization, then you can use the
stable code. However we will be designing the rest of the code around enabling
the optimization. In particular, `Unique::new` is unsafe to call, because
-putting `null` inside of it is Undefined Behaviour. Our stable Unique doesn't
+putting `null` inside of it is Undefined Behavior. Our stable Unique doesn't
need `new` to be unsafe because it doesn't make any interesting guarantees about
its contents.
initialized, Rust won't just let us dereference the location of memory to move
the value out, because that would leave the memory uninitialized! For this we
need `ptr::read`, which just copies out the bits from the target address and
-intrprets it as a value of type T. This will leave the memory at this address
+interprets it as a value of type T. This will leave the memory at this address
logically uninitialized, even though there is in fact a perfectly good instance
of T there.
% Handling Zero-Sized Types
-It's time. We're going to fight the spectre that is zero-sized types. Safe Rust
+It's time. We're going to fight the specter that is zero-sized types. Safe Rust
*never* needs to care about this, but Vec is very intensive on raw pointers and
raw allocations, which are exactly the two things that care about
zero-sized types. We need to be careful of two things:
-* The raw allocator API has undefined behaviour if you pass in 0 for an
+* The raw allocator API has undefined behavior if you pass in 0 for an
allocation size.
* raw pointer offsets are no-ops for zero-sized types, which will break our
C-style pointer iterator.
[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature
gated. This is expected to improve soon.
-- The first character has property `XID_start`
-- The remaining characters have property `XID_continue`
+Either
+
+ * The first character has property `XID_start`
+ * The remaining characters have property `XID_continue`
+
+Or
+
+ * The first character is `_`
+ * The identifier is more than one character, `_` alone is not an identifier
+ * The remaining characters have property `XID_continue`
that does _not_ occur in the set of [keywords][keywords].
### Symbols
-Symbols are a general class of printable [token](#tokens) that play structural
-roles in a variety of grammar productions. They are catalogued here for
-completeness as the set of remaining miscellaneous printable tokens that do not
+Symbols are a general class of printable [tokens](#tokens) that play structural
+roles in a variety of grammar productions. They are a
+set of remaining miscellaneous printable tokens that do not
otherwise appear as [unary operators](#unary-operator-expressions), [binary
operators](#binary-operator-expressions), or [keywords][keywords].
+They are catalogued in [the Symbols section][symbols] of the Grammar document.
+
+[symbols]: grammar.html#symbols
## Paths
# Crates and source files
Although Rust, like any other language, can be implemented by an interpreter as
-well as a compiler, the only existing implementation is a compiler —
-from now on referred to as *the* Rust compiler — and the language has
+well as a compiler, the only existing implementation is a compiler,
+and the language has
always been designed to be compiled. For these reasons, this section assumes a
compiler.
* [modules](#modules)
* [functions](#functions)
* [type definitions](grammar.html#type-definitions)
-* [structures](#structures)
+* [structs](#structs)
* [enumerations](#enumerations)
* [constant items](#constant-items)
* [static items](#static-items)
}
use foo::example::iter; // good: foo is at crate root
-// use example::iter; // bad: core is not at the crate root
+// use example::iter; // bad: example is not at the crate root
use self::baz::foobaz; // good: self refers to module 'foo'
use foo::bar::foobar; // good: foo is at crate root
### Functions
-A _function item_ defines a sequence of [statements](#statements) and an
-optional final [expression](#expressions), along with a name and a set of
-parameters. Functions are declared with the keyword `fn`. Functions declare a
+A _function item_ defines a sequence of [statements](#statements) and a
+final [expression](#expressions), along with a name and a set of
+parameters. Other than a name, all these are optional.
+Functions are declared with the keyword `fn`. Functions may declare a
set of *input* [*variables*](#variables) as parameters, through which the caller
passes arguments into the function, and the *output* [*type*](#types)
of the value the function will return to its caller on completion.
```
fn add(x: i32, y: i32) -> i32 {
- return x + y;
+ x + y
}
```
there is not sufficient context to determine the type parameters. For example,
`mem::size_of::<u32>() == 4`.
-#### Unsafety
-
-Unsafe operations are those that potentially violate the memory-safety
-guarantees of Rust's static semantics.
-
-The following language level features cannot be used in the safe subset of
-Rust:
-
-- Dereferencing a [raw pointer](#pointer-types).
-- Reading or writing a [mutable static variable](#mutable-statics).
-- Calling an unsafe function (including an intrinsic or foreign function).
-
-##### Unsafe functions
-
-Unsafe functions are functions that are not safe in all contexts and/or for all
-possible inputs. Such a function must be prefixed with the keyword `unsafe` and
-can only be called from an `unsafe` block or another `unsafe` function.
-
-##### Unsafe blocks
-
-A block of code can be prefixed with the `unsafe` keyword, to permit calling
-`unsafe` functions or dereferencing raw pointers within a safe function.
-
-When a programmer has sufficient conviction that a sequence of potentially
-unsafe operations is actually safe, they can encapsulate that sequence (taken
-as a whole) within an `unsafe` block. The compiler will consider uses of such
-code safe, in the surrounding context.
-
-Unsafe blocks are used to wrap foreign libraries, make direct use of hardware
-or implement features not directly present in the language. For example, Rust
-provides the language features necessary to implement memory-safe concurrency
-in the language but the implementation of threads and message passing is in the
-standard library.
-
-Rust's type system is a conservative approximation of the dynamic safety
-requirements, so in some cases there is a performance cost to using safe code.
-For example, a doubly-linked list is not a tree structure and can only be
-represented with reference-counted pointers in safe code. By using `unsafe`
-blocks to represent the reverse links as raw pointers, it can be implemented
-with only boxes.
-
-##### Behavior considered undefined
-
-The following is a list of behavior which is forbidden in all Rust code,
-including within `unsafe` blocks and `unsafe` functions. Type checking provides
-the guarantee that these issues are never caused by safe code.
-
-* Data races
-* Dereferencing a null/dangling raw pointer
-* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values)
- (uninitialized) memory
-* Breaking the [pointer aliasing
- rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules)
- with raw pointers (a subset of the rules used by C)
-* `&mut` and `&` follow LLVM’s scoped [noalias] model, except if the `&T`
- contains an `UnsafeCell<U>`. Unsafe code must not violate these aliasing
- guarantees.
-* Mutating non-mutable data (that is, data reached through a shared reference or
- data owned by a `let` binding), unless that data is contained within an `UnsafeCell<U>`.
-* Invoking undefined behavior via compiler intrinsics:
- * Indexing outside of the bounds of an object with `std::ptr::offset`
- (`offset` intrinsic), with
- the exception of one byte past the end which is permitted.
- * Using `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64`
- intrinsics) on overlapping buffers
-* Invalid values in primitive types, even in private fields/locals:
- * Dangling/null references or boxes
- * A value other than `false` (0) or `true` (1) in a `bool`
- * A discriminant in an `enum` not included in the type definition
- * A value in a `char` which is a surrogate or above `char::MAX`
- * Non-UTF-8 byte sequences in a `str`
-* Unwinding into Rust from foreign code or unwinding from Rust into foreign
- code. Rust's failure system is not compatible with exception handling in
- other languages. Unwinding must be caught and handled at FFI boundaries.
-
-[noalias]: http://llvm.org/docs/LangRef.html#noalias
-
-##### Behavior not considered unsafe
-
-This is a list of behavior not considered *unsafe* in Rust terms, but that may
-be undesired.
-
-* Deadlocks
-* Leaks of memory and other resources
-* Exiting without calling destructors
-* Integer overflow
- - Overflow is considered "unexpected" behavior and is always user-error,
- unless the `wrapping` primitives are used. In non-optimized builds, the compiler
- will insert debug checks that panic on overflow, but in optimized builds overflow
- instead results in wrapped values. See [RFC 560] for the rationale and more details.
-
-[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md
-
#### Diverging functions
A special kind of function can be declared with a `!` character where the
let p: Point = (41, 68);
```
-### Structures
+### Structs
-A _structure_ is a nominal [structure type](#structure-types) defined with the
+A _struct_ is a nominal [struct type](#struct-types) defined with the
keyword `struct`.
An example of a `struct` item and its use:
let px: i32 = p.x;
```
-A _tuple structure_ is a nominal [tuple type](#tuple-types), also defined with
+A _tuple struct_ is a nominal [tuple type](#tuple-types), also defined with
the keyword `struct`. For example:
```
let px: i32 = match p { Point(x, _) => x };
```
-A _unit-like struct_ is a structure without any fields, defined by leaving off
-the list of fields entirely. Such types will have a single value. For example:
+A _unit-like struct_ is a struct without any fields, defined by leaving off
+the list of fields entirely. Such a struct implicitly defines a constant of
+its type with the same name. For example:
```
+# #![feature(braced_empty_structs)]
struct Cookie;
-let c = [Cookie, Cookie, Cookie, Cookie];
+let c = [Cookie, Cookie {}, Cookie, Cookie {}];
+```
+
+is equivalent to
+
+```
+# #![feature(braced_empty_structs)]
+struct Cookie {}
+const Cookie: Cookie = Cookie {};
+let c = [Cookie, Cookie {}, Cookie, Cookie {}];
```
-The precise memory layout of a structure is not specified. One can specify a
+The precise memory layout of a struct is not specified. One can specify a
particular layout using the [`repr` attribute](#ffi-attributes).
### Enumerations
trait Shape { fn area(&self) -> f64; }
trait Circle : Shape { fn radius(&self) -> f64; }
-# impl Shape for Foo {
-# fn area(&self) -> f64 {
-# 0.0
-# }
-# }
+impl Shape for Foo {
+ fn area(&self) -> f64 {
+ 0.0
+ }
+}
impl Circle for Foo {
fn radius(&self) -> f64 {
println!("calling area: {}", self.area());
```
It is possible to define an implementation without referring to a trait. The
-methods in such an implementation can only be used as direct calls on the
-values of the type that the implementation targets. In such an implementation,
-the trait type and `for` after `impl` are omitted. Such implementations are
-limited to nominal types (enums, structs), and the implementation must appear
-in the same crate as the `self` type:
+methods in such an implementation can only be used as direct calls on the values
+of the type that the implementation targets. In such an implementation, the
+trait type and `for` after `impl` are omitted. Such implementations are limited
+to nominal types (enums, structs, trait objects), and the implementation must
+appear in the same crate as the `self` type:
```
struct Point {x: i32, y: i32}
list of names `#[macro_use(foo, bar)]` restricts the import to just those
macros named. The `extern crate` must appear at the crate root, not inside
`mod`, which ensures proper function of the [`$crate` macro
- variable](book/macros.html#the-variable-$crate).
+ variable](book/macros.html#the-variable-crate).
- `macro_reexport` on an `extern crate` — re-export the named macros.
link it into the output.
See the [macros section of the
-book](book/macros.html#scoping-and-macro-import/export) for more information on
+book](book/macros.html#scoping-and-macro-importexport) for more information on
macro scope.
- `simd` - on certain tuple structs, derive the arithmetic operators, which
lower to the target's SIMD instructions, if any; the `simd` feature gate
is necessary to use this attribute.
+- `unsafe_destructor_blind_to_params` - on `Drop::drop` method, asserts that the
+ destructor code (and all potential specializations of that code) will
+ never attempt to read from nor write to any references with lifetimes
+ that come in via generic parameters. This is a constraint we cannot
+ currently express via the type system, and therefore we rely on the
+ programmer to assert that it holds. Adding this to a Drop impl causes
+ the associated destructor to be considered "uninteresting" by the
+ Drop-Check rule, and thus it can help sidestep data ordering
+ constraints that would otherwise be introduced by the Drop-Check
+ rule. Such sidestepping of the constraints, if done incorrectly, can
+ lead to undefined behavior (in the form of reading or writing to data
+ outside of its dynamic extent), and thus this attribute has the word
+ "unsafe" in its name. To use this, the
+ `unsafe_destructor_blind_to_params` feature gate must be enabled.
- `unsafe_no_drop_flag` - on structs, remove the flag that prevents
destructors from being run twice. Destructors might be run multiple times on
the same object with this attribute. To use this, the `unsafe_no_drop_flag` feature
* `target_pointer_width = "..."` - Target pointer width in bits. This is set
to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
64-bit pointers.
+* `target_vendor = "..."` - Vendor of the target, for example `apple`, `pc`, or
+ simply `"unknown"`.
* `test` - Enabled when compiling the test harness (using the `--test` flag).
* `unix` - See `target_family`.
* `windows` - See `target_family`.
* `advanced_slice_patterns` - See the [match expressions](#match-expressions)
section for discussion; the exact semantics of
slice patterns are subject to change, so some types
- are still unstable.
+ are still unstable.
* `slice_patterns` - OK, actually, slice patterns are just scary and
completely unstable.
* `box_syntax` - Allows use of `box` expressions, the exact semantics of which
is subject to change.
+* `cfg_target_vendor` - Allows conditional compilation using the `target_vendor`
+ matcher which is subject to change.
+
* `concat_idents` - Allows use of the `concat_idents` macro, which is in many
ways insufficient for concatenating identifiers, and may be
removed entirely for something more wholesome.
terms of encapsulation).
* - `default_type_parameter_fallback` - Allows type parameter defaults to
influence type inference.
+* - `braced_empty_structs` - Allows use of empty structs and enum variants with braces.
If a feature is promoted to a language feature, then all existing programs will
start to receive compilation warnings about `#![feature]` directives which enabled
An _item declaration statement_ has a syntactic form identical to an
[item](#items) declaration within a module. Declaring an item — a
-function, enumeration, structure, type, static, trait, implementation or module
+function, enumeration, struct, type, static, trait, implementation or module
— locally within a statement block is simply a way of restricting its
scope to a narrow region containing all of its uses; it is otherwise identical
in meaning to declaring the item outside the statement block.
#### Moved and copied types
When a [local variable](#variables) is used as an
-[rvalue](#lvalues,-rvalues-and-temporaries), the variable will be copied
+[rvalue](#lvalues-rvalues-and-temporaries), the variable will be copied
if its type implements `Copy`. All others are moved.
### Literal expressions
### Path expressions
A [path](#paths) used as an expression context denotes either a local variable
-or an item. Path expressions are [lvalues](#lvalues,-rvalues-and-temporaries).
+or an item. Path expressions are [lvalues](#lvalues-rvalues-and-temporaries).
### Tuple expressions
(0); // zero in parentheses
```
-### Structure expressions
+### Struct expressions
-There are several forms of structure expressions. A _structure expression_
-consists of the [path](#paths) of a [structure item](#structures), followed by
+There are several forms of struct expressions. A _struct expression_
+consists of the [path](#paths) of a [struct item](#structs), followed by
a brace-enclosed list of one or more comma-separated name-value pairs,
-providing the field values of a new instance of the structure. A field name
+providing the field values of a new instance of the struct. A field name
can be any identifier, and is separated from its value expression by a colon.
-The location denoted by a structure field is mutable if and only if the
-enclosing structure is mutable.
+The location denoted by a struct field is mutable if and only if the
+enclosing struct is mutable.
-A _tuple structure expression_ consists of the [path](#paths) of a [structure
-item](#structures), followed by a parenthesized list of one or more
-comma-separated expressions (in other words, the path of a structure item
-followed by a tuple expression). The structure item must be a tuple structure
+A _tuple struct expression_ consists of the [path](#paths) of a [struct
+item](#structs), followed by a parenthesized list of one or more
+comma-separated expressions (in other words, the path of a struct item
+followed by a tuple expression). The struct item must be a tuple struct
item.
-A _unit-like structure expression_ consists only of the [path](#paths) of a
-[structure item](#structures).
+A _unit-like struct expression_ consists only of the [path](#paths) of a
+[struct item](#structs).
-The following are examples of structure expressions:
+The following are examples of struct expressions:
```
# struct Point { x: f64, y: f64 }
some_fn::<Cookie>(Cookie);
```
-A structure expression forms a new value of the named structure type. Note
-that for a given *unit-like* structure type, this will always be the same
+A struct expression forms a new value of the named struct type. Note
+that for a given *unit-like* struct type, this will always be the same
value.
-A structure expression can terminate with the syntax `..` followed by an
+A struct expression can terminate with the syntax `..` followed by an
expression to denote a functional update. The expression following `..` (the
-base) must have the same structure type as the new structure type being formed.
-The entire expression denotes the result of constructing a new structure (with
+base) must have the same struct type as the new struct type being formed.
+The entire expression denotes the result of constructing a new struct (with
the same type as the base expression) with the given values for the fields that
were explicitly specified and the values in the base expression for all other
fields.
A _field expression_ consists of an expression followed by a single dot and an
identifier, when not immediately followed by a parenthesized expression-list
(the latter is a [method call expression](#method-call-expressions)). A field
-expression denotes a field of a [structure](#structure-types).
+expression denotes a field of a [struct](#struct-types).
```{.ignore .field}
mystruct.myfield;
(Struct {a: 10, b: 20}).a;
```
-A field access is an [lvalue](#lvalues,-rvalues-and-temporaries) referring to
+A field access is an [lvalue](#lvalues-rvalues-and-temporaries) referring to
the value of that field. When the type providing the field inherits mutability,
it can be [assigned](#assignment-expressions) to.
### Array expressions
-An [array](#array,-and-slice-types) _expression_ is written by enclosing zero
+An [array](#array-and-slice-types) _expression_ is written by enclosing zero
or more comma-separated expressions of uniform type in square brackets.
In the `[expr ';' expr]` form, the expression after the `';'` must be a
### Index expressions
-[Array](#array,-and-slice-types)-typed expressions can be indexed by
+[Array](#array-and-slice-types)-typed expressions can be indexed by
writing a square-bracket-enclosed expression (the index) after them. When the
-array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can
+array is mutable, the resulting [lvalue](#lvalues-rvalues-and-temporaries) can
be assigned to.
Indices are zero-based, and may be of any integral type. Vector access is
let x = std::ops::Range {start: 0, end: 10};
let y = 0..10;
-assert_eq!(x,y);
+assert_eq!(x, y);
```
### Unary operator expressions
* `*`
: Dereference. When applied to a [pointer](#pointer-types) it denotes the
pointed-to location. For pointers to mutable locations, the resulting
- [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to.
+ [lvalue](#lvalues-rvalues-and-temporaries) can be assigned to.
On non-pointer types, it calls the `deref` method of the `std::ops::Deref`
trait, or the `deref_mut` method of the `std::ops::DerefMut` trait (if
implemented by the type and required for an outer expression that will or
#### Assignment expressions
An _assignment expression_ consists of an
-[lvalue](#lvalues,-rvalues-and-temporaries) expression followed by an equals
-sign (`=`) and an [rvalue](#lvalues,-rvalues-and-temporaries) expression.
+[lvalue](#lvalues-rvalues-and-temporaries) expression followed by an equals
+sign (`=`) and an [rvalue](#lvalues-rvalues-and-temporaries) expression.
Evaluating an assignment expression [either copies or
moves](#moved-and-copied-types) its right-hand operand to its left-hand
a lifetime preceding the loop expression, as in `'foo: loop{ }`. If a
label is present, then labeled `break` and `continue` expressions nested
within this loop may exit out of this loop or return control to its head.
-See [Break expressions](#break-expressions) and [Continue
+See [break expressions](#break-expressions) and [continue
expressions](#continue-expressions).
-### Break expressions
+### `break` expressions
A `break` expression has an optional _label_. If the label is absent, then
executing a `break` expression immediately terminates the innermost loop
present, then `break 'foo` terminates the loop with label `'foo`, which need not
be the innermost label enclosing the `break` expression, but must enclose it.
-### Continue expressions
+### `continue` expressions
A `continue` expression has an optional _label_. If the label is absent, then
executing a `continue` expression immediately terminates the current iteration
A `continue` expression is only permitted in the body of a loop.
-### While loops
+### `while` loops
A `while` loop begins by evaluating the boolean loop conditional expression.
If the loop conditional expression evaluates to `true`, the loop body block
loops](#infinite-loops), [break expressions](#break-expressions), and
[continue expressions](#continue-expressions) for more information.
-### For expressions
+### `for` expressions
A `for` expression is a syntactic construct for looping over elements provided
by an implementation of `std::iter::IntoIterator`.
-An example of a for loop over the contents of an array:
+An example of a `for` loop over the contents of an array:
```
# type Foo = i32;
loops](#infinite-loops), [break expressions](#break-expressions), and
[continue expressions](#continue-expressions) for more information.
-### If expressions
+### `if` expressions
An `if` expression is a conditional branch in program control. The form of an
`if` expression is a condition expression, followed by a consequent block, any
if` condition is evaluated. If all `if` and `else if` conditions evaluate to
`false` then any `else` block is executed.
-### Match expressions
+### `match` expressions
A `match` expression branches on a *pattern*. The exact form of matching that
occurs depends on the pattern. Patterns consist of some combination of
-literals, destructured arrays or enum constructors, structures and tuples,
+literals, destructured arrays or enum constructors, structs and tuples,
variable binding specifications, wildcards (`..`), and placeholders (`_`). A
`match` expression has a *head expression*, which is the value to compare to
the patterns. The type of the patterns must equal the type of the head
fields of a particular variant.
A `match` behaves differently depending on whether or not the head expression
-is an [lvalue or an rvalue](#lvalues,-rvalues-and-temporaries). If the head
+is an [lvalue or an rvalue](#lvalues-rvalues-and-temporaries). If the head
expression is an rvalue, it is first evaluated into a temporary location, and
the resulting value is sequentially compared to the patterns in the arms until
a match is found. The first arm with a matching pattern is chosen as the branch
};
```
-### If let expressions
+### `if let` expressions
An `if let` expression is semantically identical to an `if` expression but in place
of a condition expression it expects a refutable let statement. If the value of the
}
```
-### While let loops
+### `while let` loops
A `while let` loop is semantically identical to a `while` loop but in place of a
condition expression it expects a refutable let statement. If the value of the
loop body block executes and control returns to the pattern matching statement.
Otherwise, the while expression completes.
-### Return expressions
+### `return` expressions
Return expressions are denoted with the keyword `return`. Evaluating a `return`
expression moves its argument into the designated output location for the
All in-bounds elements of arrays and slices are always initialized, and access
to an array or slice is always bounds-checked.
-### Structure types
+### Struct types
A `struct` *type* is a heterogeneous product of other types, called the
*fields* of the type.[^structtype]
[^structtype]: `struct` types are analogous to `struct` types in C,
the *record* types of the ML family,
- or the *structure* types of the Lisp family.
+ or the *struct* types of the Lisp family.
New instances of a `struct` can be constructed with a [struct
-expression](#structure-expressions).
+expression](#struct-expressions).
The memory layout of a `struct` is undefined by default to allow for compiler
optimizations like field reordering, but it can be fixed with the
The fields of a `struct` may be qualified by [visibility
modifiers](#visibility-and-privacy), to allow access to data in a
-structure outside a module.
+struct outside a module.
-A _tuple struct_ type is just like a structure type, except that the fields are
+A _tuple struct_ type is just like a struct type, except that the fields are
anonymous.
-A _unit-like struct_ type is like a structure type, except that it has no
-fields. The one value constructed by the associated [structure
-expression](#structure-expressions) is the only value that inhabits such a
+A _unit-like struct_ type is like a struct type, except that it has no
+fields. The one value constructed by the associated [struct
+expression](#struct-expressions) is the only value that inhabits such a
type.
### Enumerated types
### Recursive types
Nominal types — [enumerations](#enumerated-types) and
-[structures](#structure-types) — may be recursive. That is, each `enum`
+[structs](#struct-types) — may be recursive. That is, each `enum`
constructor or `struct` field may refer, directly or indirectly, to the
enclosing `enum` or `struct` type itself. Such recursion has restrictions:
* Recursive types must include a nominal type in the recursion
(not mere [type definitions](grammar.html#type-definitions),
- or other structural types such as [arrays](#array,-and-slice-types) or [tuples](#tuple-types)).
+ or other structural types such as [arrays](#array-and-slice-types) or [tuples](#tuple-types)).
* A recursive `enum` item must have at least one non-recursive constructor
(in order to give the recursion a basis case).
* The size of a recursive type must be finite;
### Pointer types
All pointers in Rust are explicit first-class values. They can be copied,
-stored into data structures, and returned from functions. There are two
+stored into data structs, and returned from functions. There are two
varieties of pointer in Rust:
* References (`&`)
Each sub-expression is a coercion site to the respective type, e.g. the
zeroth sub-expression is a coercion site to type `U_0`.
-* Parenthesised sub-expressions (`(e)`): if the expression has type `U`, then
+* Parenthesized sub-expressions (`(e)`): if the expression has type `U`, then
the sub-expression is a coercion site to `U`.
* Blocks: if a block has type `U`, then the last expression in the block (if
### Variables
A _variable_ is a component of a stack frame, either a named function parameter,
-an anonymous [temporary](#lvalues,-rvalues-and-temporaries), or a named local
+an anonymous [temporary](#lvalues-rvalues-and-temporaries), or a named local
variable.
A _local variable_ (or *stack-local* allocation) holds a value directly,
The Rust compiler supports various methods to link crates together both
statically and dynamically. This section will explore the various methods to
link Rust crates together, and more information about native libraries can be
-found in the [ffi section of the book][ffi].
+found in the [FFI section of the book][ffi].
In one session of compilation, the compiler can generate multiple artifacts
through the usage of either command line flags or the `crate_type` attribute.
-If one or more command line flag is specified, all `crate_type` attributes will
+If one or more command line flags are specified, all `crate_type` attributes will
be ignored in favor of only building the artifacts specified by command line.
* `--crate-type=bin`, `#[crate_type = "bin"]` - A runnable executable will be
specified, then the compiler will produce each form of output at once without
having to recompile. However, this only applies for outputs specified by the
same method. If only `crate_type` attributes are specified, then they will all
-be built, but if one or more `--crate-type` command line flag is specified,
+be built, but if one or more `--crate-type` command line flags are specified,
then only those outputs will be built.
With all these different kinds of outputs, if crate A depends on crate B, then
all compilation needs, and the other options are just available if more
fine-grained control is desired over the output format of a Rust crate.
-# Appendix: Rationales and design trade-offs
+# Unsafety
+
+Unsafe operations are those that potentially violate the memory-safety
+guarantees of Rust's static semantics.
+
+The following language level features cannot be used in the safe subset of
+Rust:
+
+- Dereferencing a [raw pointer](#pointer-types).
+- Reading or writing a [mutable static variable](#mutable-statics).
+- Calling an unsafe function (including an intrinsic or foreign function).
+
+## Unsafe functions
+
+Unsafe functions are functions that are not safe in all contexts and/or for all
+possible inputs. Such a function must be prefixed with the keyword `unsafe` and
+can only be called from an `unsafe` block or another `unsafe` function.
+
+## Unsafe blocks
+
+A block of code can be prefixed with the `unsafe` keyword, to permit calling
+`unsafe` functions or dereferencing raw pointers within a safe function.
+
+When a programmer has sufficient conviction that a sequence of potentially
+unsafe operations is actually safe, they can encapsulate that sequence (taken
+as a whole) within an `unsafe` block. The compiler will consider uses of such
+code safe, in the surrounding context.
+
+Unsafe blocks are used to wrap foreign libraries, make direct use of hardware
+or implement features not directly present in the language. For example, Rust
+provides the language features necessary to implement memory-safe concurrency
+in the language but the implementation of threads and message passing is in the
+standard library.
+
+Rust's type system is a conservative approximation of the dynamic safety
+requirements, so in some cases there is a performance cost to using safe code.
+For example, a doubly-linked list is not a tree structure and can only be
+represented with reference-counted pointers in safe code. By using `unsafe`
+blocks to represent the reverse links as raw pointers, it can be implemented
+with only boxes.
+
+## Behavior considered undefined
+
+The following is a list of behavior which is forbidden in all Rust code,
+including within `unsafe` blocks and `unsafe` functions. Type checking provides
+the guarantee that these issues are never caused by safe code.
-*TODO*.
+* Data races
+* Dereferencing a null/dangling raw pointer
+* Reads of [undef](http://llvm.org/docs/LangRef.html#undefined-values)
+ (uninitialized) memory
+* Breaking the [pointer aliasing
+ rules](http://llvm.org/docs/LangRef.html#pointer-aliasing-rules)
+ with raw pointers (a subset of the rules used by C)
+* `&mut` and `&` follow LLVM’s scoped [noalias] model, except if the `&T`
+ contains an `UnsafeCell<U>`. Unsafe code must not violate these aliasing
+ guarantees.
+* Mutating non-mutable data (that is, data reached through a shared reference or
+ data owned by a `let` binding), unless that data is contained within an `UnsafeCell<U>`.
+* Invoking undefined behavior via compiler intrinsics:
+ * Indexing outside of the bounds of an object with `std::ptr::offset`
+ (`offset` intrinsic), with
+ the exception of one byte past the end which is permitted.
+ * Using `std::ptr::copy_nonoverlapping_memory` (`memcpy32`/`memcpy64`
+ intrinsics) on overlapping buffers
+* Invalid values in primitive types, even in private fields/locals:
+ * Dangling/null references or boxes
+ * A value other than `false` (0) or `true` (1) in a `bool`
+ * A discriminant in an `enum` not included in the type definition
+ * A value in a `char` which is a surrogate or above `char::MAX`
+ * Non-UTF-8 byte sequences in a `str`
+* Unwinding into Rust from foreign code or unwinding from Rust into foreign
+ code. Rust's failure system is not compatible with exception handling in
+ other languages. Unwinding must be caught and handled at FFI boundaries.
+
+[noalias]: http://llvm.org/docs/LangRef.html#noalias
+
+## Behavior not considered unsafe
+
+This is a list of behavior not considered *unsafe* in Rust terms, but that may
+be undesired.
+
+* Deadlocks
+* Leaks of memory and other resources
+* Exiting without calling destructors
+* Integer overflow
+ - Overflow is considered "unexpected" behavior and is always user-error,
+ unless the `wrapping` primitives are used. In non-optimized builds, the compiler
+ will insert debug checks that panic on overflow, but in optimized builds overflow
+ instead results in wrapped values. See [RFC 560] for the rationale and more details.
+
+[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md
# Appendix: Influences
* SML, OCaml: algebraic data types, pattern matching, type inference,
semicolon statement separation
-* C++: references, RAII, smart pointers, move semantics, monomorphisation,
+* C++: references, RAII, smart pointers, move semantics, monomorphization,
memory model
* ML Kit, Cyclone: region based memory management
* Haskell (GHC): typeclasses, type families
.rusttest { display: none; }
pre.rust { position: relative; }
-.test-arrow {
+a.test-arrow {
display: inline-block;
position: absolute;
- top: 0;
- right: 10px;
- font-size: 150%;
- -webkit-transform: scaleX(-1);
- transform: scaleX(-1);
+
+ background-color: #4e8bca;
+ color: #f5f5f5;
+ padding: 5px 10px 5px 10px;
+ border-radius: 5px;
+ font-size: 130%;
+ top: 5px;
+ right: 5px;
}
.unstable-feature {
* [Testing](testing/README.md)
* [Unit testing](testing/unit.md)
* [FFI, platform-specific code](platform.md)
-* [APIs for a changing Rust](changing/README.md)
- * [Pre-1.0 changes](changing/pre-1-0.md)
- * [Post-1.0 changes](changing/post-1-0.md)
- * [Timing unclear](changing/unclear.md)
+++ /dev/null
-% API design for a changing Rust
-
-A number of planned Rust features will drastically affect the API design
-story. This section collects some of the biggest features with concrete examples
-of how the API will change.
+++ /dev/null
-% Post-1.0 changes
-
-### Higher-kinded types
-
-* A trait encompassing both `Iterable<T>` for some fixed `T` and
- `FromIterator<U>` for _all_ `U` (where HKT comes in). The train
- could provide e.g. a default `map` method producing the same kind of
- the container, but with a new type parameter.
-
-* **Monadic-generic programming**? Can we add this without deprecating
- huge swaths of the API (including `Option::map`, `option::collect`,
- `result::collect`, `try!` etc.
+++ /dev/null
-% Pre-1.0 changes
-
-### `std` facade
-
-We should revisit some APIs in `libstd` now that the facade effort is complete.
-
-For example, the treatment of environment variables in the new
-`Command` API is waiting on access to hashtables before being
-approved.
-
-### Trait reform
-
-Potential for standard conversion traits (`to`, `into`, `as`).
-
-Probably many other opportunities here.
-
-### Unboxed closures
+++ /dev/null
-% Changes with unclear timing
-
-### Associated items
-
-* Many traits that currently take type parameters should instead use associated
- types; this will _drastically_ simplify signatures in some cases.
-
-* Associated constants would be useful in a few places, e.g. traits for
- numerics, traits for paths.
-
-### Anonymous, unboxed return types (aka `impl Trait` types)
-
-* See https://github.com/rust-lang/rfcs/pull/105
-
-* Could affect API design in several places, e.g. the `Iterator` trait.
-
-### Default type parameters
-
-We are already using this in a few places (e.g. `HashMap`), but it's
-feature-gated.
-
-### Compile-time function evaluation (CTFE)
-
-https://github.com/mozilla/rust/issues/11621
-
-### Improved constant folding
-
-https://github.com/rust-lang/rust/issues/7834
```
See
-[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try!-macro)
+[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try-macro)
for more details.
### The `Result`-`impl` pattern [FIXME]
Avoid using `#[path="..."]` directives; make the file system and
module hierarchy match, instead.
-### Use the module hirearchy to organize APIs into coherent sections. [FIXME]
+### Use the module hierarchy to organize APIs into coherent sections. [FIXME]
> **[FIXME]** Flesh this out with examples; explain what a "coherent
> section" is with examples.
>
-> The module hirearchy defines both the public and internal API of your module.
+> The module hierarchy defines both the public and internal API of your module.
> Breaking related functionality into submodules makes it understandable to both
> users and contributors to the module.
```
While it is possible to define all of `io` within a single directory,
-mirroring the module hirearchy in the directory structure makes
+mirroring the module hierarchy in the directory structure makes
submodules of `io::net` easier to find.
### Consider top-level definitions or reexports. [FIXME: needs RFC]
[`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
is defined in `io/net/tcp.rs` and reexported in the `io` module.
-### Use internal module hirearchies for organization. [FIXME: needs RFC]
+### Use internal module hierarchies for organization. [FIXME: needs RFC]
> **[FIXME]**
> - Referencing internal modules from the standard library is subject to
> becoming outdated.
-Internal module hirearchies (i.e., private submodules) may be used to
+Internal module hierarchies (i.e., private submodules) may be used to
hide implementation details that are not part of the module's API.
For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem`
To see why, consider the following situation:
-* Crate `std` defines trait `Show`.
-* Crate `url` defines type `Url`, without implementing `Show`.
+* Crate `std` defines trait `Debug`.
+* Crate `url` defines type `Url`, without implementing `Debug`.
* Crate `webapp` imports from both `std` and `url`,
-There is no way for `webapp` to add `Show` to `url`, since it defines neither.
+There is no way for `webapp` to add `Debug` to `url`, since it defines neither.
(Note: the newtype pattern can provide an efficient, but inconvenient
workaround; see [newtype for views](../types/newtype.md))
The most important common traits to implement from `std` are:
```rust
-Clone, Show, Hash, Eq
+Clone, Debug, Hash, Eq
```
#### When safe, derive or otherwise implement `Send` and `Share`. [FIXME]
* _Inference_. Since the type parameters to generic functions can usually be
inferred, generic functions can help cut down on verbosity in code where
explicit conversions or other method calls would usually be necessary. See the
- [overloading/implicits use case](#use-case:-limited-overloading-and/or-implicit-conversions)
+ [overloading/implicits use case](#use-case-limited-overloading-andor-implicit-conversions)
below.
* _Precise types_. Because generics give a _name_ to the specific type
implementing a trait, it is possible to be precise about places where that
a `Vec<T>` contains elements of a single concrete type (and, indeed, the
vector representation is specialized to lay these out in line). Sometimes
heterogeneous collections are useful; see
- [trait objects](#use-case:-trait-objects) below.
+ [trait objects](#use-case-trait-objects) below.
* _Signature verbosity_. Heavy use of generics can bloat function signatures.
**[Ed. note]** This problem may be mitigated by some language improvements; stay tuned.
> **[FIXME]** We probably want to discourage this, at least when used in a way
> that is publicly exposed.
-Traits that provide default implmentations for function can provide code reuse
+Traits that provide default implementations for function can provide code reuse
across types. For example, a `print` method can be defined across multiple
types as follows:
//!
//! The core library is a something something...
```
+
+### Explain context.
+
+Rust doesn't have special constructors, only functions that return new
+instances. These aren't visible in the automatically generated documentation
+for a type, so you should specifically link to them:
+
+``` rust
+/// An iterator that yields `None` forever after the underlying iterator
+/// yields `None` once.
+///
+/// These can be created through
+/// [`iter.fuse()`](trait.Iterator.html#method.fuse).
+pub struct Fuse<I> {
+ // ...
+}
+```
systems. It improves on current languages targeting this space by having a
number of compile-time safety checks that produce no runtime overhead, while
eliminating all data races. Rust also aims to achieve ‘zero-cost abstractions’
-even though some of these abstractions feel like those of a high-level
-language. Even then, Rust still allows precise control like a low-level
-language would.
+even though some of these abstractions feel like those of a high-level language.
+Even then, Rust still allows precise control like a low-level language would.
[rust]: https://www.rust-lang.org
[gl]: glossary.html
[bi]: bibliography.html
-After reading this introduction, you’ll want to dive into either ‘Learn Rust’
-or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you
-want to dive in with a project, or ‘Syntax and Semantics’ if you prefer to
-start small, and learn a single concept thoroughly before moving onto the next.
+After reading this introduction, you’ll want to dive into either ‘Learn Rust’ or
+‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you want
+to dive in with a project, or ‘Syntax and Semantics’ if you prefer to start
+small, and learn a single concept thoroughly before moving onto the next.
Copious cross-linking connects these parts together.
### Contributing
-The source files from which this book is generated can be found on Github:
+The source files from which this book is generated can be found on GitHub:
[github.com/rust-lang/rust/tree/master/src/doc/trpl](https://github.com/rust-lang/rust/tree/master/src/doc/trpl)
## A brief introduction to Rust
annotating types.
Rust prefers stack allocation to heap allocation: `x` is placed directly on the
-stack. However, the `Vec<T>` type allocates space for the elements of the
-vector on the heap. If you’re not familiar with this distinction, you can
-ignore it for now, or check out [‘The Stack and the Heap’][heap]. As a systems
-programming language, Rust gives you the ability to control how your memory is
-allocated, but when we’re getting started, it’s less of a big deal.
+stack. However, the `Vec<T>` type allocates space for the elements of the vector
+on the heap. If you’re not familiar with this distinction, you can ignore it for
+now, or check out [‘The Stack and the Heap’][heap]. As a systems programming
+language, Rust gives us the ability to control how our memory is allocated, but
+when we’re getting started, it’s less of a big deal.
[var]: variable-bindings.html
[macro]: macros.html
parlance, `x` is said to ‘own’ the vector. This means that when `x` goes out of
scope, the vector’s memory will be de-allocated. This is done deterministically
by the Rust compiler, rather than through a mechanism such as a garbage
-collector. In other words, in Rust, you don’t call functions like `malloc` and
-`free` yourself: the compiler statically determines when you need to allocate
-or deallocate memory, and inserts those calls itself. To err is to be human,
-but compilers never forget.
+collector. In other words, in Rust, we don’t call functions like `malloc` and
+`free` ourselves: the compiler statically determines when we need to allocate or
+deallocate memory, and inserts those calls itself. To err is to be human, but
+compilers never forget.
Let’s add another line to our example:
}
```
-We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to
-the first element of the vector. Rust’s references are similar to pointers in
-other languages, but with additional compile-time safety checks. References
-interact with the ownership system by [‘borrowing’][borrowing] what they point
-to, rather than owning it. The difference is, when the reference goes out of
-scope, it will not deallocate the underlying memory. If it did, we’d
-de-allocate twice, which is bad!
+We’ve introduced another binding, `y`. In this case, `y` is a ‘reference’ to the
+first element of the vector. Rust’s references are similar to pointers in other
+languages, but with additional compile-time safety checks. References interact
+with the ownership system by [‘borrowing’][borrowing] what they point to, rather
+than owning it. The difference is, when the reference goes out of scope, it
+won't deallocate the underlying memory. If it did, we’d de-allocate twice, which
+is bad!
[borrowing]: references-and-borrowing.html
Whew! The Rust compiler gives quite detailed errors at times, and this is one
of those times. As the error explains, while we made our binding mutable, we
-still cannot call `push`. This is because we already have a reference to an
+still can't call `push`. This is because we already have a reference to an
element of the vector, `y`. Mutating something while another reference exists
is dangerous, because we may invalidate the reference. In this specific case,
when we create the vector, we may have only allocated space for two elements.
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
* [Slice Patterns](slice-patterns.md)
* [Associated Constants](associated-constants.md)
+ * [Custom Allocators](custom-allocators.md)
* [Glossary](glossary.md)
+* [Syntax Index](syntax-index.md)
* [Bibliography](bibliography.md)
so it makes sense to provide extra command line
arguments, but this will not always be the case. In the future `rustc` may use
LLVM directly to link native libraries, in which case `link_args` will have no
-meaning. You can achieve the same effect as the `link-args` attribute with the
+meaning. You can achieve the same effect as the `link_args` attribute with the
`-C link-args` argument to `rustc`.
It is highly recommended to *not* use this attribute, and rather use the more
features on old systems or target systems which do not have the required
dependencies for your program to run.
-Static linking is supported via an alternative `libc`, `musl`. You can compile
+Static linking is supported via an alternative `libc`, [`musl`](http://www.musl-libc.org). You can compile
your own version of Rust with `musl` enabled and install it into a custom
directory with the instructions below:
$ curl -O http://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz
$ tar xf llvm-3.7.0.src.tar.xz
$ cd llvm-3.7.0.src/projects/
-llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libcxxabi-3.7.0.src.tar.xz | tar xJf -
-llvm-3.7.0.src/projects $ mv libcxxabi-3.7.0.src libcxxabi
llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz | tar xJf -
llvm-3.7.0.src/projects $ mv libunwind-3.7.0.src libunwind
llvm-3.7.0.src/projects $ mkdir libunwind/build
Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work by Eric Holk.
* [Parallel closures: a new twist on an old
idea](https://www.usenix.org/conference/hotpar12/parallel-closures-new-twist-old-idea)
- - not exactly about rust, but by nmatsakis
+ - not exactly about Rust, but by nmatsakis
* [Patina: A Formalization of the Rust Programming
Language](ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf). Early
formalization of a subset of the type system, by Eric Reed.
Rust](http://scialex.github.io/reenix.pdf). Undergrad paper by Alex
Light.
* [Evaluation of performance and productivity metrics of potential
- programming languages in the HPC environment](). Bachelor's thesis by
- Florian Wilkens. Compares C, Go and Rust.
+ programming languages in the HPC environment]
+ (http://octarineparrot.com/assets/mrfloya-thesis-ba.pdf).
+ Bachelor's thesis by Florian Wilkens. Compares C, Go and Rust.
* [Nom, a byte oriented, streaming, zero copy, parser combinators library
in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). By
Geoffroy Couprie, research for VLC.
Farnstrand's master's thesis.
* [Session Types for
Rust](http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip
- Munksgaard's master's thesis. Research for Servo.
\ No newline at end of file
+ Munksgaard's master's thesis. Research for Servo.
+* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](http://amitlevy.com/papers/tock-plos2015.pdf)
with:
```text
-error: transmute called on types with different sizes: [u8; 4] (32 bits) to u64
+error: transmute called with differently sized types: [u8; 4] (32 bits) to u64
(64 bits)
```
to check.
For large, complicated programs, it becomes useful to put some things in `RefCell`s to make things
-simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the rust compiler internals
+simpler. For example, a lot of the maps in [the `ctxt` struct][ctxt] in the Rust compiler internals
are inside this wrapper. These are only modified once (during creation, which is not right after
initialization) or a couple of times in well-separated places. However, since this struct is
pervasively used everywhere, juggling mutable and immutable pointers would be hard (perhaps
# Composition
-A common gripe when reading Rust code is with types like `Rc<RefCell<Vec<T>>>` (or even more more
+A common gripe when reading Rust code is with types like `Rc<RefCell<Vec<T>>>` (or even more
complicated compositions of such types). It's not always clear what the composition does, or why the
author chose one like this (and when one should be using such a composition in one's own code)
% Closures
-Rust not only has named functions, but anonymous functions as well. Anonymous
-functions that have an associated environment are called ‘closures’, because they
-close over an environment. Rust has a really great implementation of them, as
-we’ll see.
+Sometimes it is useful to wrap up a function and _free variables_ for better
+clarity and reuse. The free variables that can be used come from the
+enclosing scope and are ‘closed over’ when used in the function. From this, we
+get the name ‘closures’ and Rust provides a really great implementation of
+them, as we’ll see.
# Syntax
```
You’ll notice a few things about closures that are a bit different from regular
-functions defined with `fn`. The first is that we did not need to
+named functions defined with `fn`. The first is that we did not need to
annotate the types of arguments the closure takes or the values it returns. We
can:
assert_eq!(2, plus_one(1));
```
-But we don’t have to. Why is this? Basically, it was chosen for ergonomic reasons.
-While specifying the full type for named functions is helpful with things like
-documentation and type inference, the types of closures are rarely documented
-since they’re anonymous, and they don’t cause the kinds of error-at-a-distance
-problems that inferring named function types can.
+But we don’t have to. Why is this? Basically, it was chosen for ergonomic
+reasons. While specifying the full type for named functions is helpful with
+things like documentation and type inference, the full type signatures of
+closures are rarely documented since they’re anonymous, and they don’t cause
+the kinds of error-at-a-distance problems that inferring named function types
+can.
-The second is that the syntax is similar, but a bit different. I’ve added spaces
-here for easier comparison:
+The second is that the syntax is similar, but a bit different. I’ve added
+spaces here for easier comparison:
```rust
fn plus_one_v1 (x: i32) -> i32 { x + 1 }
# Closures and their environment
-Closures are called such because they ‘close over their environment’. It
-looks like this:
+The environment for a closure can include bindings from its enclosing scope in
+addition to parameters and local bindings. It looks like this:
```rust
let num = 5;
it, while a `move` closure is self-contained. This means that you cannot
generally return a non-`move` closure from a function, for example.
-But before we talk about taking and returning closures, we should talk some more
-about the way that closures are implemented. As a systems language, Rust gives
-you tons of control over what your code does, and closures are no different.
+But before we talk about taking and returning closures, we should talk some
+more about the way that closures are implemented. As a systems language, Rust
+gives you tons of control over what your code does, and closures are no
+different.
# Closure implementation
# some_closure(1) }
```
-Because `Fn` is a trait, we can bound our generic with it. In this case, our closure
-takes a `i32` as an argument and returns an `i32`, and so the generic bound we use
-is `Fn(i32) -> i32`.
+Because `Fn` is a trait, we can bound our generic with it. In this case, our
+closure takes a `i32` as an argument and returns an `i32`, and so the generic
+bound we use is `Fn(i32) -> i32`.
There’s one other key point here: because we’re bounding a generic with a
trait, this will get monomorphized, and therefore, we’ll be doing static
```
Right. Because we have a reference, we need to give it a lifetime. But
-our `factory()` function takes no arguments, so elision doesn’t kick in
-here. What lifetime can we choose? `'static`:
+our `factory()` function takes no arguments, so
+[elision](lifetimes.html#lifetime-elision) doesn’t kick in here. Then what
+choices do we have? Try `'static`:
```rust,ignore
fn factory() -> &'static (Fn(i32) -> i32) {
```text
error: mismatched types:
expected `&'static core::ops::Fn(i32) -> i32`,
- found `[closure <anon>:7:9: 7:20]`
+ found `[closure@<anon>:7:9: 7:20]`
(expected &-ptr,
found closure) [E0308]
|x| x + num
```
This error is letting us know that we don’t have a `&'static Fn(i32) -> i32`,
-we have a `[closure <anon>:7:9: 7:20]`. Wait, what?
+we have a `[closure@<anon>:7:9: 7:20]`. Wait, what?
Because each closure generates its own environment `struct` and implementation
of `Fn` and friends, these types are anonymous. They exist just solely for
-this closure. So Rust shows them as `closure <anon>`, rather than some
+this closure. So Rust shows them as `closure@<anon>`, rather than some
autogenerated name.
-But why doesn’t our closure implement `&'static Fn`? Well, as we discussed before,
-closures borrow their environment. And in this case, our environment is based
-on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime
-of the stack frame. So if we returned this closure, the function call would be
-over, the stack frame would go away, and our closure is capturing an environment
-of garbage memory!
-
-So what to do? This _almost_ works:
+The error also points out that the return type is expected to be a reference,
+but what we are trying to return is not. Further, we cannot directly assign a
+`'static` lifetime to an object. So we'll take a different approach and return
+a ‘trait object’ by `Box`ing up the `Fn`. This _almost_ works:
```rust,ignore
fn factory() -> Box<Fn(i32) -> i32> {
# }
```
-We use a trait object, by `Box`ing up the `Fn`. There’s just one last problem:
+There’s just one last problem:
```text
error: closure may outlive the current function, but it borrows `num`,
^~~~~~~~~~~
```
-We still have a reference to the parent stack frame. With one last fix, we can
-make this work:
+Well, as we discussed before, closures borrow their environment. And in this
+case, our environment is based on a stack-allocated `5`, the `num` variable
+binding. So the borrow has a lifetime of the stack frame. So if we returned
+this closure, the function call would be over, the stack frame would go away,
+and our closure is capturing an environment of garbage memory! With one last
+fix, we can make this work:
```rust
fn factory() -> Box<Fn(i32) -> i32> {
Plugins can extend [Rust's lint
infrastructure](../reference.html#lint-check-attributes) with additional checks for
-code style, safety, etc. You can see
-[`src/test/auxiliary/lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
-for a full example, the core of which is reproduced here:
+code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
+that warns about any item named `lintme`.
```ignore
-declare_lint!(TEST_LINT, Warn,
- "Warn about items named 'lintme'");
+#![feature(plugin_registrar)]
+#![feature(box_syntax, rustc_private)]
+
+extern crate syntax;
+
+// Load rustc as a plugin to get macros
+#[macro_use]
+extern crate rustc;
+
+use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
+ EarlyLintPassObject, LintArray};
+use rustc::plugin::Registry;
+use syntax::ast;
+
+declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
struct Pass;
fn get_lints(&self) -> LintArray {
lint_array!(TEST_LINT)
}
+}
- fn check_item(&mut self, cx: &Context, it: &ast::Item) {
- if it.ident.name == "lintme" {
+impl EarlyLintPass for Pass {
+ fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
+ if it.ident.name.as_str() == "lintme" {
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
}
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_lint_pass(box Pass as LintPassObject);
+ reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
}
```
### `Send`
The first trait we're going to talk about is
-[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates
-to the compiler that something of this type is able to have ownership transferred
+[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it
+indicates that something of this type is able to have ownership transferred
safely between threads.
This is important to enforce certain restrictions. For example, if we have a
down the channel and to the other thread. Therefore, we'd ensure that `Send` was
implemented for that type.
-In the opposite way, if we were wrapping a library with FFI that isn't
+In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't
threadsafe, we wouldn't want to implement `Send`, and so the compiler will help
us enforce that it can't leave the current thread.
+[ffi]: ffi.html
+
### `Sync`
The second of these traits is called [`Sync`](../std/marker/trait.Sync.html).
-When a type `T` implements `Sync`, it indicates to the compiler that something
+When a type `T` implements `Sync`, it indicates that something
of this type has no possibility of introducing memory unsafety when used from
-multiple threads concurrently.
-
-For example, sharing immutable data with an atomic reference count is
-threadsafe. Rust provides a type like this, `Arc<T>`, and it implements `Sync`,
-so it is safe to share between threads.
+multiple threads concurrently through shared references. This implies that
+types which don't have [interior mutability](mutability.html) are inherently
+`Sync`, which includes simple primitive types (like `u8`) and aggregate types
+containing them.
+
+For sharing references across threads, Rust provides a wrapper type called
+`Arc<T>`. `Arc<T>` implements `Send` and `Sync` if and only if `T` implements
+both `Send` and `Sync`. For example, an object of type `Arc<RefCell<U>>` cannot
+be transferred across threads because
+[`RefCell`](choosing-your-guarantees.html#refcellt) does not implement
+`Sync`, consequently `Arc<RefCell<U>>` would not implement `Send`.
These two traits allow you to use the type system to make strong guarantees
about the properties of your code under concurrency. Before we demonstrate
}
```
-The `thread::spawn()` method accepts a closure, which is executed in a
+The `thread::spawn()` method accepts a [closure](closures.html), which is executed in a
new thread. It returns a handle to the thread, that can be used to
wait for the child thread to finish and extract its result:
So, we need some type that lets us have more than one reference to a value and
that we can share between threads, that is it must implement `Sync`.
-We'll use `Arc<T>`, rust's standard atomic reference count type, which
+We'll use `Arc<T>`, Rust's standard atomic reference count type, which
wraps a value up with some extra runtime bookkeeping which allows us to
share the ownership of the value between multiple references at the same time.
something else to persuade the borrow checker we know what we're doing.
It looks like we need some type that allows us to safely mutate a shared value,
-for example a type that that can ensure only one thread at a time is able to
+for example a type that can ensure only one thread at a time is able to
mutate the value inside it at any one time.
For that, we can use the `Mutex<T>` type!
}
```
+Note that the value of `i` is bound (copied) to the closure and not shared
+among the threads.
-If we'd tried to use `Mutex<T>` without wrapping it in an `Arc<T>` we would have
-seen another error like:
-
-```text
-error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
- thread::spawn(move || {
- ^~~~~~~~~~~~~
-note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
- thread::spawn(move || {
- ^~~~~~~~~~~~~
-```
-
-You see, [`Mutex`](../std/sync/struct.Mutex.html) has a
-[`lock`](../std/sync/struct.Mutex.html#method.lock)
-method which has this signature:
+Also note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of
+[`Mutex`](../std/sync/struct.Mutex.html) has this signature:
```ignore
fn lock(&self) -> LockResult<MutexGuard<T>>
```
-and because `Send` is not implemented for `MutexGuard<T>`, we couldn't have
-transferred the guard across thread boundaries on it's own.
+and because `Send` is not implemented for `MutexGuard<T>`, the guard cannot
+cross thread boundaries, ensuring thread-locality of lock acquire and release.
Let's examine the body of the thread more closely:
fn main() {
let (tx, rx) = mpsc::channel();
- for _ in 0..10 {
+ for i in 0..10 {
let tx = tx.clone();
thread::spawn(move || {
- let answer = 42;
+ let answer = i * i;
tx.send(answer);
});
}
- rx.recv().ok().expect("Could not receive answer");
+ for _ in 0..10 {
+ println!("{}", rx.recv().unwrap());
+ }
}
```
-A `u32` is `Send` because we can make a copy. So we create a thread, ask it to calculate
-the answer, and then it `send()`s us the answer over the channel.
+Here we create 10 threads, asking each to calculate the square of a number (`i`
+at the time of `spawn()`), and then `send()` back the answer over the channel.
## Panics
As for how to enable or disable these switches, if you’re using Cargo,
they get set in the [`[features]` section][features] of your `Cargo.toml`:
-[features]: http://doc.crates.io/manifest.html#the-%5Bfeatures%5D-section
+[features]: http://doc.crates.io/manifest.html#the-features-section
```toml
[features]
First, both `extern crate` and `use` allow renaming the thing that is being
imported. So the crate is still called "phrases", but here we will refer
to it as "sayings". Similarly, the first `use` statement pulls in the
-`japanese::farewells` module from the crate, but makes it available as
-`jp_farewells` as opposed to simply `farewells`. This can help to avoid
+`japanese::greetings` module from the crate, but makes it available as
+`ja_greetings` as opposed to simply `greetings`. This can help to avoid
ambiguity when importing similarly-named items from different places.
The second `use` statement uses a star glob to bring in _all_ symbols from the
globbing to compress three `use` statements into one (this sort of syntax
may be familiar if you've written Linux shell scripts before). The
uncompressed form of this statement would be:
+
```rust,ignore
use sayings::english;
use sayings::english::greetings as en_greetings;
use sayings::english::farewells as en_farewells;
```
+
As you can see, the curly brackets compress `use` statements for several items
under the same path, and in this context `self` just refers back to that path.
Note: The curly brackets cannot be nested or mixed with star globbing.
--- /dev/null
+% Custom Allocators
+
+Allocating memory isn't always the easiest thing to do, and while Rust generally
+takes care of this by default it often becomes necessary to customize how
+allocation occurs. The compiler and standard library currently allow switching
+out the default global allocator in use at compile time. The design is currently
+spelled out in [RFC 1183][rfc] but this will walk you through how to get your
+own allocator up and running.
+
+[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1183-swap-out-jemalloc.md
+
+# Default Allocator
+
+The compiler currently ships two default allocators: `alloc_system` and
+`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
+are just normal Rust crates and contain an implementation of the routines to
+allocate and deallocate memory. The standard library is not compiled assuming
+either one, and the compiler will decide which allocator is in use at
+compile-time depending on the type of output artifact being produced.
+
+Binaries generated by the compiler will use `alloc_jemalloc` by default (where
+available). In this situation the compiler "controls the world" in the sense of
+it has power over the final link. Primarily this means that the allocator
+decision can be left up the compiler.
+
+Dynamic and static libraries, however, will use `alloc_system` by default. Here
+Rust is typically a 'guest' in another application or another world where it
+cannot authoritatively decide what allocator is in use. As a result it resorts
+back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
+memory.
+
+# Switching Allocators
+
+Although the compiler's default choices may work most of the time, it's often
+necessary to tweak certain aspects. Overriding the compiler's decision about
+which allocator is in use is done simply by linking to the desired allocator:
+
+```rust,no_run
+#![feature(alloc_system)]
+
+extern crate alloc_system;
+
+fn main() {
+ let a = Box::new(4); // allocates from the system allocator
+ println!("{}", a);
+}
+```
+
+In this example the binary generated will not link to jemalloc by default but
+instead use the system allocator. Conversely to generate a dynamic library which
+uses jemalloc by default one would write:
+
+```rust,ignore
+#![feature(alloc_jemalloc)]
+#![crate_type = "dylib"]
+
+extern crate alloc_jemalloc;
+
+pub fn foo() {
+ let a = Box::new(4); // allocates from jemalloc
+ println!("{}", a);
+}
+# fn main() {}
+```
+
+# Writing a custom allocator
+
+Sometimes even the choices of jemalloc vs the system allocator aren't enough and
+an entirely new custom allocator is required. In this you'll write your own
+crate which implements the allocator API (e.g. the same as `alloc_system` or
+`alloc_jemalloc`). As an example, let's take a look at a simplified and
+annotated version of `alloc_system`
+
+```rust,no_run
+# // only needed for rustdoc --test down below
+# #![feature(lang_items)]
+// The compiler needs to be instructed that this crate is an allocator in order
+// to realize that when this is linked in another allocator like jemalloc should
+// not be linked in
+#![feature(allocator)]
+#![allocator]
+
+// Allocators are not allowed to depend on the standard library which in turn
+// requires an allocator in order to avoid circular dependencies. This crate,
+// however, can use all of libcore.
+#![feature(no_std)]
+#![no_std]
+
+// Let's give a unique name to our custom allocator
+#![crate_name = "my_allocator"]
+#![crate_type = "rlib"]
+
+// Our system allocator will use the in-tree libc crate for FFI bindings. Note
+// that currently the external (crates.io) libc cannot be used because it links
+// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why
+// this specifically requires the in-tree version.
+#![feature(libc)]
+extern crate libc;
+
+// Listed below are the five allocation functions currently required by custom
+// allocators. Their signatures and symbol names are not currently typechecked
+// by the compiler, but this is a future extension and are required to match
+// what is found below.
+//
+// Note that the standard `malloc` and `realloc` functions do not provide a way
+// to communicate alignment so this implementation would need to be improved
+// with respect to alignment in that aspect.
+
+#[no_mangle]
+pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
+ unsafe { libc::malloc(size as libc::size_t) as *mut u8 }
+}
+
+#[no_mangle]
+pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
+ unsafe { libc::free(ptr as *mut libc::c_void) }
+}
+
+#[no_mangle]
+pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
+ _align: usize) -> *mut u8 {
+ unsafe {
+ libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
+ }
+}
+
+#[no_mangle]
+pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
+ _size: usize, _align: usize) -> usize {
+ old_size // this api is not supported by libc
+}
+
+#[no_mangle]
+pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
+ size
+}
+
+# // just needed to get rustdoc to test this
+# fn main() {}
+# #[lang = "panic_fmt"] fn panic_fmt() {}
+# #[lang = "eh_personality"] fn eh_personality() {}
+# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
+```
+
+After we compile this crate, it can be used as follows:
+
+```rust,ignore
+extern crate my_allocator;
+
+fn main() {
+ let a = Box::new(8); // allocates memory via our custom allocator crate
+ println!("{}", a);
+}
+```
+
+# Custom allocator limitations
+
+There are a few restrictions when working with custom allocators which may cause
+compiler errors:
+
+* Any one artifact may only be linked to at most one allocator. Binaries,
+ dylibs, and staticlibs must link to exactly one allocator, and if none have
+ been explicitly chosen the compiler will choose one. On the other hand rlibs
+ do not need to link to an allocator (but still can).
+
+* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the
+ `liballoc` crate currently) and an `#[allocator]` crate cannot transitively
+ depend on a crate which needs an allocator (e.g. circular dependencies are not
+ allowed). This basically means that allocators must restrict themselves to
+ libcore currently.
> dining room, furnished with a circular table, surrounded by five chairs, each
> labelled by the name of the philosopher who was to sit in it. They sat
> anticlockwise around the table. To the left of each philosopher there was
-> laid a golden fork, and in the centre stood a large bowl of spaghetti, which
+> laid a golden fork, and in the center stood a large bowl of spaghetti, which
> was constantly replenished. A philosopher was expected to spend most of
> their time thinking; but when they felt hungry, they went to the dining
> room, sat down in their own chair, picked up their own fork on their left,
6. ... ? All the forks are taken, but nobody can eat!
There are different ways to solve this problem. We’ll get to our solution in
-the tutorial itself. For now, let’s get started modelling the problem itself.
+the tutorial itself. For now, let’s get started modeling the problem itself.
We’ll start with the philosophers:
```rust
Inside the thread, all we do is call `eat()` on `p`. Also note that the call to `thread::spawn` lacks a trailing semicolon, making this an expression. This distinction is important, yielding the correct return value. For more details, read [Expressions vs. Statements][es].
-[es]: functions.html#expressions-vs.-statements
+[es]: functions.html#expressions-vs-statements
```rust,ignore
}).collect();
fn eat(&self, table: &Table) {
let _left = table.forks[self.left].lock().unwrap();
+ thread::sleep_ms(150);
let _right = table.forks[self.right].lock().unwrap();
println!("{} is eating.", self.name);
```rust,ignore
fn eat(&self, table: &Table) {
let _left = table.forks[self.left].lock().unwrap();
+ thread::sleep_ms(150);
let _right = table.forks[self.right].lock().unwrap();
println!("{} is eating.", self.name);
}
```
-We have two new lines. We’ve also added an argument, `table`. We access the
+We have three new lines. We’ve added an argument, `table`. We access the
`Table`’s list of forks, and then use `self.left` and `self.right` to access
the fork at that particular index. That gives us access to the `Mutex` at that
index, and we call `lock()` on it. If the mutex is currently being accessed by
-someone else, we’ll block until it becomes available.
+someone else, we’ll block until it becomes available. We have also a call to
+`thread::sleep_ms` between the moment first fork is picked and the moment the
+second forked is picked, as the process of picking up the fork is not
+immediate.
The call to `lock()` might fail, and if it does, we want to crash. In this
case, the error that could happen is that the mutex is [‘poisoned’][poison],
you look at the pattern, it’s all consistent until the very end. Monsieur
Foucault should have `4, 0` as arguments, but instead, has `0, 4`. This is what
prevents deadlock, actually: one of our philosophers is left handed! This is
-one way to solve the problem, and in my opinion, it’s the simplest.
+one way to solve the problem, and in my opinion, it’s the simplest. If you
+change the order of the parameters, you will be able to observe the deadlock
+taking place.
```rust,ignore
let handles: Vec<_> = philosophers.into_iter().map(|p| {
documentation. This is important when documenting things like enums:
```rust
-/// The `Option` type. See [the module level documentation](../) for more.
+/// The `Option` type. See [the module level documentation](index.html) for more.
enum Option<T> {
/// No value
None,
The above works, but this does not:
```rust,ignore
-/// The `Option` type. See [the module level documentation](../) for more.
+/// The `Option` type. See [the module level documentation](index.html) for more.
enum Option<T> {
None, /// No value
Some(T), /// Some value `T`
```
This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is
-correct: documentation comments apply to the thing after them, and there's
+correct: documentation comments apply to the thing after them, and there's
nothing after that last comment.
[rc-new]: https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new
```
You'll notice that you don't need a `fn main()` or anything here. `rustdoc` will
-automatically add a main() wrapper around your code, and in the right place.
+automatically add a `main()` wrapper around your code, and in the right place.
For example:
```rust
}
```
-Here's the full algorithm rustdoc uses to postprocess examples:
+Here's the full algorithm rustdoc uses to preprocess examples:
1. Any leading `#![foo]` attributes are left intact as crate attributes.
2. Some common `allow` attributes are inserted, including
it. At the same time, it's just there to satisfy the compiler, so hiding
it makes the example more clear. You can use this technique to explain
longer examples in detail, while still preserving the testability of your
-documentation. For example, this code:
-
-```rust
-let x = 5;
-let y = 6;
-println!("{}", x + y);
-```
-
-Here's an explanation, rendered:
+documentation.
-First, we set `x` to five:
+For example, imagine that we wanted to document this code:
```rust
let x = 5;
-# let y = 6;
-# println!("{}", x + y);
-```
-
-Next, we set `y` to six:
-
-```rust
-# let x = 5;
let y = 6;
-# println!("{}", x + y);
-```
-
-Finally, we print the sum of `x` and `y`:
-
-```rust
-# let x = 5;
-# let y = 6;
println!("{}", x + y);
```
-Here's the same explanation, in raw text:
+We might want the documentation to end up looking like this:
> First, we set `x` to five:
>
-> ```text
+> ```rust
> let x = 5;
> # let y = 6;
> # println!("{}", x + y);
>
> Next, we set `y` to six:
>
-> ```text
+> ```rust
> # let x = 5;
> let y = 6;
> # println!("{}", x + y);
>
> Finally, we print the sum of `x` and `y`:
>
-> ```text
+> ```rust
> # let x = 5;
> # let y = 6;
> println!("{}", x + y);
> ```
+To keep each code block testable, we want the whole program in each block, but
+we don't want the reader to see every line every time. Here's what we put in
+our source code:
+
+```text
+ First, we set `x` to five:
+
+ ```text
+ let x = 5;
+ # let y = 6;
+ # println!("{}", x + y);
+ ```
+
+ Next, we set `y` to six:
+
+ ```text
+ # let x = 5;
+ let y = 6;
+ # println!("{}", x + y);
+ ```
+
+ Finally, we print the sum of `x` and `y`:
+
+ ```text
+ # let x = 5;
+ # let y = 6;
+ println!("{}", x + y);
+ ```
+```
+
By repeating all parts of the example, you can ensure that your example still
compiles, while only showing the parts that are relevant to that part of your
explanation.
### Running documentation tests
-To run the tests, either
+To run the tests, either:
```bash
$ rustdoc --test path/to/my/crate/root.rs
## `doc` attributes
-At a deeper level, documentation comments are sugar for documentation attributes:
+At a deeper level, documentation comments are syntactic sugar for documentation
+attributes:
```rust
/// this
```rust
//! this
-#![doc="/// this"]
+#![doc="this"]
```
You won't often see this attribute used for writing documentation, but it
pub use foo::bar;
```
-This will create documentation for bar both inside the documentation for the
+This will create documentation for `bar` both inside the documentation for the
crate `foo`, as well as the documentation for your crate. It will use the same
documentation in both places.
pub use foo::bar;
```
+## Missing documentation
+
+Sometimes you want to make sure that every single public thing in your project
+is documented, especially when you are working on a library. Rust allows you to
+to generate warnings or errors, when an item is missing documentation.
+To generate warnings you use `warn`:
+
+```rust
+#![warn(missing_docs)]
+```
+
+And to generate errors you use `deny`:
+
+```rust,ignore
+#![deny(missing_docs)]
+```
+
+There are cases where you want to disable these warnings/errors to explicitly
+leave something undocumented. This is done by using `allow`:
+
+```rust
+#[allow(missing_docs)]
+struct Undocumented;
+```
+
+You might even want to hide items from the documentation completely:
+
+```rust
+#[doc(hidden)]
+struct Hidden;
+```
+
### Controlling HTML
You can control a few aspects of the HTML that `rustdoc` generates through the
Here's another example that is slightly less contrived. A program that accepts
an integer as an argument, doubles it and prints it.
+<span id="code-unwrap-double"></span>
+
```rust,should_panic
use std::env;
simple, but to do that, we will first need to explore the `Option` and `Result`
types. Both of these types have a method called `unwrap` defined on them.
-## The `Option` type
+### The `Option` type
-The `Option` type is
-[defined in the standard library][1]:
+The `Option` type is [defined in the standard library][5]:
```rust
enum Option<T> {
programmer to handle that absence. Let's take a look at an example that tries
to find a character in a string:
+<span id="code-option-ex-string-find"></span>
+
```rust
// Searches `haystack` for the Unicode character `needle`. If one is found, the
// byte offset of the character is returned. Otherwise, `None` is returned.
}
```
-Notice that when this function finds a matching character, it doen't just
+Notice that when this function finds a matching character, it doesn't just
return the `offset`. Instead, it returns `Some(offset)`. `Some` is a variant or
a *value constructor* for the `Option` type. You can think of it as a function
with the type `fn<T>(value: T) -> Option<T>`. Correspondingly, `None` is also a
means that you, as the programmer, must handle the case when an `Option<T>` is
`None` instead of `Some(t)`.
-But wait, what about `unwrap` used in [`unwrap-double`](#code-unwrap-double)?
+But wait, what about `unwrap`,which we used [`previously`](#code-unwrap-double)?
There was no case analysis there! Instead, the case analysis was put inside the
`unwrap` method for you. You could define it yourself if you want:
+<span id="code-option-def-unwrap"></span>
+
```rust
enum Option<T> {
None,
### Composing `Option<T>` values
-In [`option-ex-string-find`](#code-option-ex-string-find-2)
+In an [example from before](#code-option-ex-string-find),
we saw how to use `find` to discover the extension in a file name. Of course,
not all file names have a `.` in them, so it's possible that the file name has
no extension. This *possibility of absence* is encoded into the types using
```rust
# fn find(_: &str, _: char) -> Option<usize> { None }
// Returns the extension of the given file name, where the extension is defined
-// as all characters proceding the first `.`.
+// as all characters proceeding the first `.`.
// If `file_name` has no `.`, then `None` is returned.
fn extension_explicit(file_name: &str) -> Option<&str> {
match find(file_name, '.') {
Rust has parametric polymorphism, so it is very easy to define a combinator
that abstracts this pattern:
+<span id="code-option-map"></span>
+
```rust
fn map<F, T, A>(option: Option<T>, f: F) -> Option<A> where F: FnOnce(T) -> A {
match option {
```rust
# fn find(_: &str, _: char) -> Option<usize> { None }
// Returns the extension of the given file name, where the extension is defined
-// as all characters proceding the first `.`.
+// as all characters proceeding the first `.`.
// If `file_name` has no `.`, then `None` is returned.
fn extension(file_name: &str) -> Option<&str> {
find(file_name, '.').map(|i| &file_name[i+1..])
}
```
-One other pattern that we find is very common is assigning a default value to
-the case when an `Option` value is `None`. For example, maybe your program
-assumes that the extension of a file is `rs` even if none is present. As you
-might imagine, the case analysis for this is not specific to file
-extensions - it can work with any `Option<T>`:
+One other pattern we commonly find is assigning a default value to the case
+when an `Option` value is `None`. For example, maybe your program assumes that
+the extension of a file is `rs` even if none is present. As you might imagine,
+the case analysis for this is not specific to file extensions - it can work
+with any `Option<T>`:
```rust
fn unwrap_or<T>(option: Option<T>, default: T) -> T {
The `Result` type is also
[defined in the standard library][6]:
+<span id="code-result-def"></span>
+
```rust
enum Result<T, E> {
Ok(T),
### The `Result` type alias idiom
In the standard library, you may frequently see types like
-`Result<i32>`. But wait, [we defined `Result`](#code-result-def-1) to
+`Result<i32>`. But wait, [we defined `Result`](#code-result-def) to
have two type parameters. How can we get away with only specifying
one? The key is to define a `Result` type alias that *fixes* one of
the type parameters to a particular type. Usually the fixed type is
(from `env::args()`) means the user didn't invoke the program correctly. We
could just use a `String` to describe the error. Let's try:
+<span id="code-error-double-string"></span>
+
```rust
use std::env;
(N.B. The `AsRef<Path>` is used because those are the
[same bounds used on
`std::fs::File::open`](../std/fs/struct.File.html#method.open).
-This makes it ergnomic to use any kind of string as a file path.)
+This makes it ergonomic to use any kind of string as a file path.)
There are three different errors that can occur here:
an `i32`) by `2`. If an error had occurred before that point, this operation
would have been skipped because of how `map` is defined.
-`map_err` is the trick the makes all of this work. `map_err` is just like
+`map_err` is the trick that makes all of this work. `map_err` is just like
`map`, except it applies a function to the `Err(...)` value of a `Result`. In
this case, we want to convert all of our errors to one type: `String`. Since
both `io::Error` and `num::ParseIntError` implement `ToString`, we can call the
Here is a simplified definition of a `try!` macro:
+<span id="code-try-def-simple"></span>
+
```rust
macro_rules! try {
($e:expr) => (match $e {
[defined in the standard
library](../std/convert/trait.From.html):
+<span id="code-from-def"></span>
+
```rust
trait From<T> {
fn from(T) -> Self;
There is a really important pattern to recognize here. Both `err1` and `err2`
have the *same type*. This is because they are existentially quantified types,
-or trait objects. In particularly, their underlying type is *erased* from the
+or trait objects. In particular, their underlying type is *erased* from the
compiler's knowledge, so it truly sees `err1` and `err2` as exactly the same.
Additionally, we constructed `err1` and `err2` using precisely the same
function call: `From::from`. This is because `From::from` is overloaded on both
}
```
-This is not it's real definition. It's real definition is
+This is not its real definition. Its real definition is
[in the standard library](../std/macro.try!.html):
+<span id="code-try-def"></span>
+
```rust
macro_rules! try {
($e:expr) => (match $e {
Earlier, we promised that we could get rid of the `map_err` calls. Indeed, all
we have to do is pick a type that `From` works with. As we saw in the previous
-section, `From` has an impl that let's it convert any error type into a
+section, `From` has an impl that lets it convert any error type into a
`Box<Error>`:
```rust
We're not going to spend a lot of time on setting up a project with
Cargo because it is already covered well in [the Cargo
-chapter](../book/hello-cargo) and [Cargo's documentation][14].
+chapter](../book/hello-cargo.html) and [Cargo's documentation][14].
To get started from scratch, run `cargo new --bin city-pop` and make sure your
`Cargo.toml` looks something like this:
## Argument parsing
-Let's get argument parsing out of the way. we won't go into too much
+Let's get argument parsing out of the way. We won't go into too much
detail on Getopts, but there is [some good documentation][15]
describing it. The short story is that Getopts generates an argument
parser and a help message from a vector of options (The fact that it
is a vector is hidden behind a struct and a set of methods). Once the
parsing is done, we can decode the program arguments into a Rust
struct. From there, we can get information about the flags, for
-instance, wether they were passed in, and what arguments they
+instance, whether they were passed in, and what arguments they
had. Here's our program with the appropriate `extern crate`
statements, and the basic argument setup for Getopts:
let mut opts = Options::new();
opts.optflag("h", "help", "Show this usage message.");
-
+
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
Err(e) => { panic!(e.to_string()) }
}
let data_path = args[1].clone();
let city = args[2].clone();
-
+
// Do stuff with information
}
```
that's done, we set up our argument flags, in this case a simplistic
help message flag. Once we have the argument flags set up, we use
`Options.parse` to parse the argument vector (starting from index one,
-becouse index 0 is the program name). If this was successful, we
+because index 0 is the program name). If this was successful, we
assign matches to the parsed object, if not, we panic. Once past that,
we test if the user passed in the help flag, and if so print the usage
message. The option help messages are constructed by Getopts, so all
let mut opts = Options::new();
opts.optflag("h", "help", "Show this usage message.");
-
+
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
Err(e) => { panic!(e.to_string()) }
};
-
+
if matches.opt_present("h") {
print_usage(&program, opts);
return;
}
-
+
let data_file = args[1].clone();
let data_path = Path::new(&data_file);
let city = args[2].clone();
-
+
let file = fs::File::open(data_path).unwrap();
let mut rdr = csv::Reader::from_reader(file);
-
+
for row in rdr.decode::<Row>() {
let row = row.unwrap();
-
+
if row.city == city {
println!("{}, {}: {:?}",
row.city, row.country,
print_usage(&program, opts);
return;
}
-
+
let data_file = args[1].clone();
let data_path = Path::new(&data_file);
let city = args[2].clone();
data. This means we probably should be able to accept input on stdin. But maybe
we like the current format too—so let's have both!
-Adding support for stdin is actually quite easy. There are only two things we
+Adding support for stdin is actually quite easy. There are only three things we
have to do:
1. Tweak the program arguments so that a single parameter—the
...
let file = matches.opt_str("f");
let data_file = file.as_ref().map(Path::new);
-
+
let city = if !matches.free.is_empty() {
matches.free[0].clone()
} else {
...
```
-In this peice of code, we take `file` (which has the type
+In this piece of code, we take `file` (which has the type
`Option<String>`), and convert it to a type that `search` can use, in
-this case, `&Option<AsRef<Path>>`. Do do this, we take a reference of
+this case, `&Option<AsRef<Path>>`. To do this, we take a reference of
file, and map `Path::new` onto it. In this case, `as_ref()` converts
the `Option<String>` into an `Option<&str>`, and from there, we can
execute `Path::new` to the content of the optional, and return the
be used in shell scripts.
So let's start by adding the flags. Like before, we need to tweak the usage
-string and add a flag to the Option variable. Once were done that, Getopts does the rest:
+string and add a flag to the Option variable. Once we've done that, Getopts does the rest:
```rust,ignore
...
let mut opts = Options::new();
opts.optopt("f", "file", "Choose an input file, instead of using STDIN.", "NAME");
opts.optflag("h", "help", "Show this usage message.");
-opts.optflag("q", "quit", "Silences errors and warnings.");
+opts.optflag("q", "quiet", "Silences errors and warnings.");
...
```
and
[`Error`](../std/error/trait.Error.html)
impls to make the [`try!`](../std/macro.try!.html)
- macro more ergnomic.
+ macro more ergonomic.
* If you're writing a library and your code can produce errors, define your own
error type and implement the
[`std::error::Error`](../std/error/trait.Error.html)
% Getting Started
-This first section of the book will get you going with Rust and its tooling.
+This first section of the book will get us going with Rust and its tooling.
First, we’ll install Rust. Then, the classic ‘Hello World’ program. Finally,
we’ll talk about Cargo, Rust’s build system and package manager.
In the example above `x` and `y` have arity 2. `z` has arity 3.
+### Bounds
+
+Bounds are constraints on a type or [trait][traits]. For example, if a bound
+is placed on the argument a function takes, types passed to that function
+must abide by that constraint.
+
+[traits]: traits.html
+
### DST (Dynamically Sized Type)
A type without a statically known size or alignment. ([more info][link])
-[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-(dsts)
+[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-dsts
### Expression
We’ll need to take user input, and then print the result as output. As such, we
need the `io` library from the standard library. Rust only imports a few things
by default into every program, [the ‘prelude’][prelude]. If it’s not in the
-prelude, you’ll have to `use` it directly.
+prelude, you’ll have to `use` it directly. There is also a second ‘prelude’, the
+[`io` prelude][ioprelude], which serves a similar function: you import it, and it
+imports a number of useful, `io`-related things.
[prelude]: ../std/prelude/index.html
+[ioprelude]: ../std/io/prelude/index.html
```rust,ignore
fn main() {
For example, they’re [immutable][immutable] by default. That’s why our example
uses `mut`: it makes a binding mutable, rather than immutable. `let` doesn’t
-take a name on the left hand side, it actually accepts a
+take a name on the left hand side of the assignment, it actually accepts a
‘[pattern][patterns]’. We’ll use patterns later. It’s easy enough
to use for now:
`Foo::Bar` or a `Foo::Baz`. We use the `::` to indicate the
namespace for a particular `enum` variant.
-The [`Ordering`][ordering] enum has three possible variants: `Less`, `Equal`,
+The [`Ordering`][ordering] `enum` has three possible variants: `Less`, `Equal`,
and `Greater`. The `match` statement takes a value of a type, and lets you
create an ‘arm’ for each possible value. Since we have three types of
`Ordering`, we have three arms:
This is how you generally move from ‘crash on error’ to ‘actually handle the
error’, by switching from `ok().expect()` to a `match` statement. The `Result`
-returned by `parse()` is an enum just like `Ordering`, but in this case, each
+returned by `parse()` is an `enum` just like `Ordering`, but in this case, each
variant has some data associated with it: `Ok` is a success, and `Err` is a
-failure. Each contains more information: the successful parsed integer, or an
+failure. Each contains more information: the successfully parsed integer, or an
error type. In this case, we `match` on `Ok(num)`, which sets the inner value
of the `Ok` to the name `num`, and then we just return it on the right-hand
side. In the `Err` case, we don’t care what kind of error it is, so we just
[cratesio]: http://doc.crates.io
-Cargo manages three things: building your code, downloading the dependencies
-your code needs, and building those dependencies. At first, your program doesn’t
-have any dependencies, so we’ll only be using the first part of its
-functionality. Eventually, we’ll add more. Since we started off by using Cargo,
-it'll be easy to add later.
+Cargo manages three things: building our code, downloading the dependencies our
+code needs, and building those dependencies. At first, our program doesn’t have
+any dependencies, so we’ll only be using the first part of its functionality.
+Eventually, we’ll add more. Since we started off by using Cargo, it'll be easy
+to add later.
-If we installed Rust via the official installers we will also have Cargo. If we
-installed Rust some other way, we may want to [check the Cargo
-README][cargoreadme] for specific instructions about installing it.
+If you installed Rust via the official installers you will also have Cargo. If
+you installed Rust some other way, you may want to
+[check the Cargo README][cargoreadme] for specific instructions about installing
+it.
[cargoreadme]: https://github.com/rust-lang/cargo#installing-cargo-from-nightlies
```bash
$ mkdir src
$ mv main.rs src/main.rs
-$ rm main # or main.exe on Windows
+$ rm main # or 'rm main.exe' on Windows
```
-Note that since we're creating an executable, we retain `main.rs` as the source
-filename. If we want to make a library instead, we should use `lib.rs`. This
-convention is used by Cargo to successfully compile our projects, but it can be
-overridden if we wish. Custom file locations for the entry point can be
-specified with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file.
+> Note: since we're creating an executable, we retain `main.rs` as the source
+> filename. If we want to make a library instead, we should use `lib.rs`. This
+> convention is used by Cargo to successfully compile our projects, but it can
+> be overridden if we wish. Custom file locations for the entry point can be
+> specified with a [`[lib]` or `[[bin]]`][crates-custom] key in the TOML file.
[crates-custom]: http://doc.crates.io/manifest.html#configuring-a-target
-Cargo expects your source files to live inside a `src` directory. That leaves
-the top level for other things, like READMEs, license information, and anything
-not related to your code. Cargo helps us keep our projects nice and tidy. A
-place for everything, and everything in its place.
+Cargo expects our source files to live inside a `src` directory. That leaves the
+top level for other things, like READMEs, license information, and anything not
+related to our code. Cargo helps us keep our projects nice and tidy. A place for
+everything, and everything in its place.
Next, our configuration file:
```bash
-$ editor Cargo.toml
+$ editor Cargo.toml # or 'notepad Cargo.toml' on Windows
```
-Make sure to get this name right: you need the capital `C`!
+Make sure to get this name right: we need the capital `C`!
Put this inside:
things to get all of the parts to properly compile. With Cargo, as our project
grows, we can just run `cargo build`, and it’ll work the right way.
-When your project is finally ready for release, you can use
-`cargo build --release` to compile your project with optimizations.
+When our project is finally ready for release, we can use `cargo build
+--release` to compile our project with optimizations.
You'll also notice that Cargo has created a new file: `Cargo.lock`.
version = "0.0.1"
```
-The `Cargo.lock` file is used by Cargo to keep track of dependencies in your application.
-Right now, we don’t have any, so it’s a bit sparse. You won't ever need
-to touch this file yourself, just let Cargo handle it.
+The `Cargo.lock` file is used by Cargo to keep track of dependencies in our
+application. Right now, we don’t have any, so it’s a bit sparse. We won't ever
+need to touch this file ourselves, just let Cargo handle it.
That’s it! We’ve successfully built `hello_world` with Cargo. Even though our
-program is simple, it’s using much of the real tooling that you’ll use for the
-rest of your Rust career. You can expect to do this to get started with
-virtually all Rust projects:
+program is simple, it’s using much of the real tooling that we’ll use for the
+rest of our Rust career. We can expect to do this to get started with virtually
+all Rust projects:
```bash
$ git clone someurl.com/foo
## A New Project
-You don’t have to go through this whole process every time you want to start a
-new project! Cargo has the ability to make a bare-bones project directory in
-which you can start developing right away.
+We don’t have to go through this whole process every time we want to start a new
+project! Cargo has the ability to make a bare-bones project directory in which
+we can start developing right away.
-To start a new project with Cargo, use `cargo new`:
+To start a new project with Cargo, we use `cargo new`:
```bash
$ cargo new hello_world --bin
```
-We’re passing `--bin` because our goal is to get straight to making an executable application, as opposed to a library. Executables are often called ‘binaries.’ (as in `/usr/bin`, if you’re on a Unix system)
+We’re passing `--bin` because our goal is to get straight to making an
+executable application, as opposed to a library. Executables are often called
+‘binaries.’ (as in `/usr/bin`, if we’re on a Unix system)
Let's check out what Cargo has generated for us:
1 directory, 2 files
```
-If you don't have the `tree` command, you can probably get it from your
+If we don't have the `tree` command, we can probably get it from our
distribution’s package manager. It’s not necessary, but it’s certainly useful.
This is all we need to get started. First, let’s check out `Cargo.toml`:
```
Cargo has populated this file with reasonable defaults based off the arguments
-you gave it and your `git` global configuration. You may notice that Cargo has
+we gave it and our `git` global configuration. You may notice that Cargo has
also initialized the `hello_world` directory as a `git` repository.
Here’s what’s in `src/main.rs`:
}
```
-Cargo has generated a "Hello World!" for us, and you’re ready to start coding! Cargo
-has its own [guide][guide] which covers Cargo’s features in much more depth.
+Cargo has generated a "Hello World!" for us, and we’re ready to start coding!
+Cargo has its own [guide][guide] which covers Cargo’s features in much more
+depth.
[guide]: http://doc.crates.io/guide.html
-Now that you’ve got the tools down, let’s actually learn more about the Rust
-language itself. These are the basics that will serve you well through the rest
-of your time with Rust.
+Now that we’ve got the tools down, let’s actually learn more about the Rust
+language itself. These are the basics that will serve us well through the rest
+of our time with Rust.
You have two options: Dive into a project with ‘[Learn Rust][learnrust]’, or
-start from the bottom and work your way up with ‘[Syntax and
-Semantics][syntax]’. More experienced systems programmers will probably prefer
-‘Learn Rust’, while those from dynamic backgrounds may enjoy either. Different
-people learn differently! Choose whatever’s right for you.
+start from the bottom and work your way up with
+‘[Syntax and Semantics][syntax]’. More experienced systems programmers will
+probably prefer ‘Learn Rust’, while those from dynamic backgrounds may enjoy
+either. Different people learn differently! Choose whatever’s right for you.
[learnrust]: learn-rust.html
[syntax]: syntax-and-semantics.html
% Hello, world!
-Now that you have Rust installed, let’s write your first Rust program. It’s
-traditional to make your first program in any new language one that prints the
+Now that we have Rust installed, let’s write our first Rust program. It’s
+traditional to make our first program in any new language one that prints the
text “Hello, world!” to the screen. The nice thing about starting with such a
-simple program is that you can verify that your compiler isn’t just installed,
-but also working properly. And printing information to the screen is a pretty
-common thing to do.
+simple program is that we can verify that our compiler isn’t just installed, but
+also working properly. And printing information to the screen is a pretty common
+thing to do.
-The first thing that we need to do is make a file to put our code in. I like
-to make a `projects` directory in my home directory, and keep all my projects
-there. Rust does not care where your code lives.
+The first thing that we need to do is make a file to put our code in. I like to
+make a `projects` directory in my home directory, and keep all my projects
+there. Rust doesn't care where our code lives.
This actually leads to one other concern we should address: this guide will
-assume that you have basic familiarity with the command line. Rust itself makes
-no specific demands on your editing tooling, or where your code lives. If you
-prefer an IDE to the command line, you may want to check out
-[SolidOak][solidoak], or wherever plugins are for your favorite IDE. There are
-a number of extensions of varying quality in development by the community. The
-Rust team also ships [plugins for various editors][plugins]. Configuring your
+assume that we have basic familiarity with the command line. Rust itself makes
+no specific demands on our editing tooling, or where our code lives. If we
+prefer an IDE to the command line, we may want to check out
+[SolidOak][solidoak], or wherever plugins are for our favorite IDE. There are a
+number of extensions of varying quality in development by the community. The
+Rust team also ships [plugins for various editors][plugins]. Configuring our
editor or IDE is out of the scope of this tutorial, so check the documentation
-for your setup, specifically.
+for our setup, specifically.
[solidoak]: https://github.com/oakes/SolidOak
[plugins]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md
$ cd hello_world
```
-If you’re on Windows and not using PowerShell, the `~` may not work. Consult
-the documentation for your shell for more details.
+If we’re on Windows and not using PowerShell, the `~` may not work. Consult the
+documentation for our shell for more details.
Let’s make a new source file next. We’ll call our file `main.rs`. Rust files
-always end in a `.rs` extension. If you’re using more than one word in your
-filename, use an underscore: `hello_world.rs` rather than `helloworld.rs`.
+always end in a `.rs` extension, and if we’re using more than one word in a
+Rust filename, we use an underscore: for example, `linked_list.rs`, not
+`linkedlist.rs` or `LinkedList.rs`.
-Now that you’ve got your file open, type this in:
+Now that we’ve got our file open, type this in:
```rust
fn main() {
}
```
-Save the file, and then type this into your terminal window:
+Save the file, and then type this into our terminal window:
```bash
$ rustc main.rs
entirely. We’ll get to it later.
You’ll also note that the function is wrapped in curly braces (`{` and `}`).
-Rust requires these around all function bodies. It is also considered good
-style to put the opening curly brace on the same line as the function
-declaration, with one space in between.
+Rust requires these around all function bodies. It is also considered good style
+to put the opening curly brace on the same line as the function declaration,
+with one space in between.
Next up is this line:
This line does all of the work in our little program. There are a number of
details that are important here. The first is that it’s indented with four
spaces, not tabs. Please configure your editor of choice to insert four spaces
-with the tab key. We provide some [sample configurations for various
-editors][configs].
+with the tab key. We provide some
+[sample configurations for various editors][configs].
[configs]: https://github.com/rust-lang/rust/tree/master/src/etc/CONFIGS.md
-The second point is the `println!()` part. This is calling a Rust [macro][macro],
-which is how metaprogramming is done in Rust. If it were a function instead, it
-would look like this: `println()`. For our purposes, we don’t need to worry
-about this difference. Just know that sometimes, you’ll see a `!`, and that
-means that you’re calling a macro instead of a normal function. Rust implements
-`println!` as a macro rather than a function for good reasons, but that's an
-advanced topic. One last thing to mention: Rust’s macros are significantly
-different from C macros, if you’ve used those. Don’t be scared of using macros.
-We’ll get to the details eventually, you’ll just have to trust us for now.
+The second point is the `println!()` part. This is calling a Rust
+[macro][macro], which is how metaprogramming is done in Rust. If it were a
+function instead, it would look like this: `println()`. For our purposes, we
+don’t need to worry about this difference. Just know that sometimes, we’ll see a
+`!`, and that means that we’re calling a macro instead of a normal function.
+Rust implements `println!` as a macro rather than a function for good reasons,
+but that's an advanced topic. One last thing to mention: Rust’s macros are
+significantly different from C macros, if you’ve used those. Don’t be scared of
+using macros. We’ll get to the details eventually, you’ll just have to take it
+on trust for now.
[macro]: macros.html
Next, `"Hello, world!"` is a ‘string’. Strings are a surprisingly complicated
topic in a systems programming language, and this is a ‘statically allocated’
-string. If you want to read further about allocation, check out
-[the stack and the heap][allocation], but you don’t need to right now if you
-don’t want to. We pass this string as an argument to `println!`, which prints the
-string to the screen. Easy enough!
+string. If you want to read further about allocation, check out [the stack and
+the heap][allocation], but you don’t need to right now if you don’t want to. We
+pass this string as an argument to `println!`, which prints the string to the
+screen. Easy enough!
[allocation]: the-stack-and-the-heap.html
$ rustc main.rs
```
-This is similar to `gcc` or `clang`, if you come from a C or C++ background. Rust
-will output a binary executable. You can see it with `ls`:
+This is similar to `gcc` or `clang`, if you come from a C or C++ background.
+Rust will output a binary executable. We can see it with `ls`:
```bash
$ ls
```
There are now two files: our source code, with the `.rs` extension, and the
-executable (`main.exe` on Windows, `main` everywhere else)
+executable (`main.exe` on Windows, `main` everywhere else).
```bash
$ ./main # or main.exe on Windows
This prints out our `Hello, world!` text to our terminal.
-If you come from a dynamic language like Ruby, Python, or JavaScript,
-you may not be used to these two steps being separate. Rust is an
-‘ahead-of-time compiled language’, which means that you can compile a program,
-give it to someone else, and they don't need to have Rust installed. If you
-give someone a `.rb` or `.py` or `.js` file, they need to have a
-Ruby/Python/JavaScript implementation installed, but you just need one command
-to both compile and run your program. Everything is a tradeoff in language
-design, and Rust has made its choice.
+If you come from a dynamic language like Ruby, Python, or JavaScript, you may
+not be used to these two steps being separate. Rust is an ‘ahead-of-time
+compiled language’, which means that we can compile a program, give it to
+someone else, and they don't need to have Rust installed. If we give someone a
+`.rb` or `.py` or `.js` file, they need to have a Ruby/Python/JavaScript
+implementation installed, but we just need one command to both compile and run
+our program. Everything is a tradeoff in language design, and Rust has made its
+choice.
Congratulations! You have officially written a Rust program. That makes you a
Rust programmer! Welcome. 🎊🎉👍
Next, I'd like to introduce you to another tool, Cargo, which is used to write
real-world Rust programs. Just using `rustc` is nice for simple things, but as
-your project grows, you'll want something to help you manage all of the options
-that it has, and to make it easy to share your code with other people and
+our project grows, we'll want something to help us manage all of the options
+that it has, and to make it easy to share our code with other people and
projects.
the value to the identifiers in the pattern, then evaluates the expression. If
the pattern doesn’t match, nothing happens.
-If you’d rather to do something else when the pattern does not match, you can
+If you want to do something else when the pattern does not match, you can
use `else`:
```rust
loop {
match option {
Some(x) => println!("{}", x),
- _ => break,
+ None => break,
}
}
```
% Installing Rust
The first step to using Rust is to install it! There are a number of ways to
-install Rust, but the easiest is to use the `rustup` script. If you're on Linux
-or a Mac, all you need to do is this:
+install Rust, but the easiest is to use the `rustup` script. If we're on Linux
+or a Mac, all we need to do is this:
-> Note: you don't need to type in the `$`s, they just indicate the start of
-> each command. You’ll see many tutorials and examples around the web that
-> follow this convention: `$` for commands run as your regular user, and
-> `#` for commands you should be running as an administrator.
+> Note: we don't need to type in the `$`s, they are there to indicate the start of
+> each command. We’ll see many tutorials and examples around the web that
+> follow this convention: `$` for commands run as our regular user, and `#` for
+> commands we should be running as an administrator.
```bash
$ curl -sf -L https://static.rust-lang.org/rustup.sh | sh
```
-If you're concerned about the [potential insecurity][insecurity] of using `curl
-| sh`, please keep reading and see our disclaimer below. And feel free to
-use a two-step version of the installation and examine our installation script:
+If we're concerned about the [potential insecurity][insecurity] of using `curl |
+sh`, please keep reading and see our disclaimer below. And feel free to use a
+two-step version of the installation and examine our installation script:
```bash
$ curl -f -L https://static.rust-lang.org/rustup.sh -O
[insecurity]: http://curlpipesh.tumblr.com
If you're on Windows, please download the appropriate [installer][install-page].
-**NOTE:** By default, the Windows installer will not add Rust to the %PATH%
-system variable. If this is the only version of Rust you are installing and you
-want to be able to run it from the command line, click on "Advanced" on the
-install dialog and on the "Product Features" page ensure "Add to PATH" is
-installed on the local hard drive.
+
+> Note: By default, the Windows installer won't add Rust to the %PATH% system
+> variable. If this is the only version of Rust we are installing and we want to
+> be able to run it from the command line, click on "Advanced" on the install
+> dialog and on the "Product Features" page ensure "Add to PATH" is installed on
+> the local hard drive.
[install-page]: https://www.rust-lang.org/install.html
## Uninstalling
If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
-Not every programming language is great for everyone. Just run the uninstall
-script:
+Not every programming language is great for everyone. We can run the
+uninstall script:
```bash
$ sudo /usr/local/lib/rustlib/uninstall.sh
```
-If you used the Windows installer, just re-run the `.msi` and it will give you
-an uninstall option.
+If we used the Windows installer, we can re-run the `.msi` and it will give
+us an uninstall option.
## That disclaimer we promised
-Some people, and somewhat rightfully so, get very upset when we tell you to
-`curl | sh`. Basically, when you do this, you are trusting that the good
-people who maintain Rust aren't going to hack your computer and do bad things.
-That's a good instinct! If you're one of those people, please check out the
-documentation on [building Rust from Source][from-source], or [the official
-binary downloads][install-page].
+Some people, and somewhat rightfully so, get very upset when we tell them to
+`curl | sh`. Their concern is that `curl | sh` implicitly requires you to trust
+that the good people who maintain Rust aren't going to hack your computer and
+do bad things — and even having accepted that, there is still the possibility
+that the Rust website has been hacked and the `rustup` script compromised.
+
+Being wary of such possibilities is a good instinct! If you're uncomfortable
+using `curl | sh` for reasons like these, please check out the documentation on
+[building Rust from Source][from-source], or
+[the official binary downloads][install-page].
[from-source]: https://github.com/rust-lang/rust#building-from-source
## Platform support
-Oh, we should also mention the officially supported platforms:
-
-* Windows (7, 8, Server 2008 R2)
-* Linux (2.6.18 or later, various distributions), x86 and x86-64
-* OSX 10.7 (Lion) or greater, x86 and x86-64
-
-We extensively test Rust on these platforms, and a few others, too, like
-Android. But these are the ones most likely to work, as they have the most
-testing.
-
-Finally, a comment about Windows. Rust considers Windows to be a first-class
-platform upon release, but if we're honest, the Windows experience isn't as
-integrated as the Linux/OS X experience is. We're working on it! If anything
-does not work, it is a bug. Please let us know if that happens. Each and every
-commit is tested against Windows just like any other platform.
+The Rust compiler runs on, and compiles to, a great number of platforms, though
+not all platforms are equally supported. Rust's support levels are organized
+into three tiers, each with a different set of guarantees.
+
+Platforms are identified by their "target triple" which is the string to inform
+the compiler what kind of output should be produced. The columns below indicate
+whether the corresponding component works on the specified platform.
+
+### Tier 1
+
+Tier 1 platforms can be thought of as "guaranteed to build and work".
+Specifically they will each satisfy the following requirements:
+
+* Automated testing is set up to run tests for the platform.
+* Landing changes to the `rust-lang/rust` repository's master branch is gated on
+ tests passing.
+* Official release artifacts are provided for the platform.
+* Documentation for how to use and how to build the platform is available.
+
+| Target | std |rustc|cargo| notes |
+|-------------------------------|-----|-----|-----|----------------------------|
+| `x86_64-pc-windows-msvc` | ✓ | ✓ | ✓ | 64-bit MSVC (Windows 7+) |
+| `i686-pc-windows-gnu` | ✓ | ✓ | ✓ | 32-bit MinGW (Windows 7+) |
+| `x86_64-pc-windows-gnu` | ✓ | ✓ | ✓ | 64-bit MinGW (Windows 7+) |
+| `i686-apple-darwin` | ✓ | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) |
+| `x86_64-apple-darwin` | ✓ | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) |
+| `i686-unknown-linux-gnu` | ✓ | ✓ | ✓ | 32-bit Linux (2.6.18+) |
+| `x86_64-unknown-linux-gnu` | ✓ | ✓ | ✓ | 64-bit Linux (2.6.18+) |
+
+### Tier 2
+
+Tier 2 platforms can be thought of as "guaranteed to build". Automated tests are
+not run so it's not guaranteed to produce a working build, but platforms often
+work to quite a good degree and patches are always welcome! Specifically, these
+platforms are required to have each of the following:
+
+* Automated building is set up, but may not be running tests.
+* Landing changes to the `rust-lang/rust` repository's master branch is gated on
+ platforms **building**. Note that this means for some platforms only the
+ standard library is compiled, but for others the full bootstrap is run.
+* Official release artifacts are provided for the platform.
+
+| Target | std |rustc|cargo| notes |
+|-------------------------------|-----|-----|-----|----------------------------|
+| `i686-pc-windows-msvc` | ✓ | ✓ | ✓ | 32-bit MSVC (Windows 7+) |
+
+### Tier 3
+
+Tier 3 platforms are those which Rust has support for, but landing changes is
+not gated on the platform either building or passing tests. Working builds for
+these platforms may be spotty as their reliability is often defined in terms of
+community contributions. Additionally, release artifacts and installers are not
+provided, but there may be community infrastructure producing these in
+unofficial locations.
+
+| Target | std |rustc|cargo| notes |
+|-------------------------------|-----|-----|-----|----------------------------|
+| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL |
+| `arm-linux-androideabi` | ✓ | | | ARM Android |
+| `i686-linux-android` | ✓ | | | 32-bit x86 Android |
+| `aarch64-linux-android` | ✓ | | | ARM64 Android |
+| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) |
+| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) |
+| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) |
+| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) |
+| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) |
+| `powerpc-unknown-linux-gnu` | ✓ | | | PowerPC Linux (2.6.18+) |
+| `i386-apple-ios` | ✓ | | | 32-bit x86 iOS |
+| `x86_64-apple-ios` | ✓ | | | 64-bit x86 iOS |
+| `armv7-apple-ios` | ✓ | | | ARM iOS |
+| `armv7s-apple-ios` | ✓ | | | ARM iOS |
+| `aarch64-apple-ios` | ✓ | | | ARM64 iOS |
+| `i686-unknown-freebsd` | ✓ | ✓ | | 32-bit FreeBSD |
+| `x86_64-unknown-freebsd` | ✓ | ✓ | | 64-bit FreeBSD |
+| `x86_64-unknown-openbsd` | ✓ | ✓ | | 64-bit OpenBSD |
+| `x86_64-unknown-netbsd` | ✓ | ✓ | | 64-bit NetBSD |
+| `x86_64-unknown-bitrig` | ✓ | ✓ | | 64-bit Bitrig |
+| `x86_64-unknown-dragonfly` | ✓ | ✓ | | 64-bit DragonFlyBSD |
+| `x86_64-rumprun-netbsd` | ✓ | | | 64-bit NetBSD Rump Kernel |
+| `i686-pc-windows-msvc` (XP) | ✓ | | | Windows XP support |
+| `x86_64-pc-windows-msvc` (XP) | ✓ | | | Windows XP support |
+
+Note that this table can be expanded over time, this isn't the exhaustive set of
+tier 3 platforms that will ever be!
## After installation
-If you've got Rust installed, you can open up a shell, and type this:
+If we've got Rust installed, we can open up a shell, and type this:
```bash
$ rustc --version
```
-You should see the version number, commit hash, and commit date. If you just
-installed version 1.2.0, you should see:
+You should see the version number, commit hash, and commit date.
-```bash
-rustc 1.2.0 (082e47636 2015-08-03)
-```
+If you do, Rust has been installed successfully! Congrats!
-If you did, Rust has been installed successfully! Congrats!
-
-If you didn't and you're on Windows, check that Rust is in your %PATH% system
+If you don't and you're on Windows, check that Rust is in your %PATH% system
variable. If it isn't, run the installer again, select "Change" on the "Change,
repair, or remove installation" page and ensure "Add to PATH" is installed on
the local hard drive.
-This installer also installs a copy of the documentation locally, so you can
-read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
-On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
-to.
-
-If not, there are a number of places where you can get help. The easiest is
-[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
-[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
-(a silly nickname we call ourselves), and we can help you out. Other great
-resources include [the user’s forum][users], and
-[Stack Overflow][stackoverflow].
+This installer also installs a copy of the documentation locally, so we can read
+it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location. On
+Windows, it's in a `share/doc` directory, inside the directory to which Rust was
+installed.
+
+If not, there are a number of places where we can get help. The easiest is
+[the #rust IRC channel on irc.mozilla.org][irc], which we can access through
+[Mibbit][mibbit]. Click that link, and we'll be chatting with other Rustaceans
+(a silly nickname we call ourselves) who can help us out. Other great resources
+include [the user’s forum][users], and [Stack Overflow][stackoverflow].
[irc]: irc://irc.mozilla.org/#rust
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
`for` loops aren't the only thing that uses iterators, however. Writing your
own iterator involves implementing the `Iterator` trait. While doing that is
outside of the scope of this guide, Rust provides a number of useful iterators
-to accomplish various tasks. Before we talk about those, we should talk about a
-Rust anti-pattern. And that's using ranges like this.
+to accomplish various tasks. But first, a few notes about limitations of ranges.
-Yes, we just talked about how ranges are cool. But ranges are also very
-primitive. For example, if you needed to iterate over the contents of a vector,
-you may be tempted to write this:
+Ranges are very primitive, and we often can use better alternatives. Consider the
+following Rust anti-pattern: using ranges to emulate a C-style `for` loop. Let’s
+suppose you needed to iterate over the contents of a vector. You may be tempted
+to write this:
```rust
let nums = vec![1, 2, 3];
talk about what you do want instead.
There are three broad classes of things that are relevant here: iterators,
-*iterator adapters*, and *consumers*. Here's some definitions:
+*iterator adaptors*, and *consumers*. Here's some definitions:
* *iterators* give you a sequence of values.
-* *iterator adapters* operate on an iterator, producing a new iterator with a
+* *iterator adaptors* operate on an iterator, producing a new iterator with a
different output sequence.
* *consumers* operate on an iterator, producing some final set of values.
.find(|x| *x > 42);
match greater_than_forty_two {
- Some(_) => println!("We got some numbers!"),
- None => println!("No numbers found :("),
+ Some(_) => println!("Found a match!"),
+ None => println!("No match found :("),
}
```
`find` takes a closure, and works on a reference to each element of an
iterator. This closure returns `true` if the element is the element we're
-looking for, and `false` otherwise. Because we might not find a matching
-element, `find` returns an `Option` rather than the element itself.
+looking for, and `false` otherwise. `find` returns the first element satisfying
+the specified predicate. Because we might not find a matching element, `find`
+returns an `Option` rather than the element itself.
Another important consumer is `fold`. Here's what it looks like:
These two basic iterators should serve you well. There are some more
advanced iterators, including ones that are infinite.
-That's enough about iterators. Iterator adapters are the last concept
+That's enough about iterators. Iterator adaptors are the last concept
we need to talk about with regards to iterators. Let's get to it!
-## Iterator adapters
+## Iterator adaptors
-*Iterator adapters* take an iterator and modify it somehow, producing
+*Iterator adaptors* take an iterator and modify it somehow, producing
a new iterator. The simplest one is called `map`:
```rust,ignore
If you are trying to execute a closure on an iterator for its side effects,
just use `for` instead.
-There are tons of interesting iterator adapters. `take(n)` will return an
-iterator over the next `n` elements of the original iterator. Note that this
-has no side effect on the original iterator. Let's try it out with our infinite
-iterator from before:
+There are tons of interesting iterator adaptors. `take(n)` will return an
+iterator over the next `n` elements of the original iterator. Let's try it out
+with an infinite iterator:
```rust
for i in (1..).take(5) {
`filter()` is an adapter that takes a closure as an argument. This closure
returns `true` or `false`. The new iterator `filter()` produces
-only the elements that that closure returns `true` for:
+only the elements that the closure returns `true` for:
```rust
for i in (1..100).filter(|&x| x % 2 == 0) {
This will give you a vector containing `6`, `12`, `18`, `24`, and `30`.
-This is just a small taste of what iterators, iterator adapters, and consumers
+This is just a small taste of what iterators, iterator adaptors, and consumers
can help you with. There are a number of really useful iterators, and you can
write your own as well. Iterators provide a safe, efficient way to manipulate
all kinds of lists. They're a little unusual at first, but if you play with
% Lifetimes
-This guide is one of three presenting Rust’s ownership system. This is one of
+This guide is three of three presenting Rust’s ownership system. This is one of
Rust’s most unique and compelling features, with which Rust developers should
become quite acquainted. Ownership is how Rust achieves its largest goal,
memory safety. There are a few distinct concepts, each with its own chapter:
Lending out a reference to a resource that someone else owns can be
complicated. For example, imagine this set of operations:
-- I acquire a handle to some kind of resource.
-- I lend you a reference to the resource.
-- I decide I’m done with the resource, and deallocate it, while you still have
+1. I acquire a handle to some kind of resource.
+2. I lend you a reference to the resource.
+3. I decide I’m done with the resource, and deallocate it, while you still have
your reference.
-- You decide to use the resource.
+4. You decide to use the resource.
Uh oh! Your reference is pointing to an invalid resource. This is called a
dangling pointer or ‘use after free’, when the resource is memory.
```
The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime
-associated with it, but the compiler lets you elide them in common cases.
+associated with it, but the compiler lets you elide (i.e. omit, see
+["Lifetime Elision"][lifetime-elision] below) them in common cases.
Before we get to that, though, let’s break the explicit example down:
+[lifetime-elision]: #lifetime-elision
+
```rust,ignore
fn bar<'a>(...)
```
fn get_mut(&mut self) -> &mut T; // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
-fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
-fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
+fn args<T:ToCStr>(&mut self, args: &[T]) -> &mut Command; // elided
+fn args<'a, 'b, T:ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded
fn new(buf: &mut [u8]) -> BufWriter; // elided
-fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
+fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded
```
`&self` if it’s a reference, and `&mut self` if it’s a mutable reference.
Because we took the `&self` parameter to `area`, we can use it just like any
other parameter. Because we know it’s a `Circle`, we can access the `radius`
-just like we would with any other `struct`.
+just like we would with any other `struct`.
We should default to using `&self`, as you should prefer borrowing over taking
ownership, as well as taking immutable references over mutable ones. Here’s an
> You may have one or the other of these two kinds of borrows, but not both at
> the same time:
->
+>
> * one or more references (`&T`) to a resource,
> * exactly one mutable reference (`&mut T`).
this is undesirable, and can be avoided with the `#![no_std]`
attribute attached to the crate.
-```ignore
-// a minimal library
-#![crate_type="lib"]
-#![feature(no_std)]
-#![no_std]
-# // fn main() {} tricked you, rustdoc!
-```
-
Obviously there's more to life than just libraries: one can use
`#[no_std]` with an executable, controlling the entry point is
possible in two ways: the `#[start]` attribute, or overriding the
in the same format as C:
```rust
-#![feature(lang_items, start, no_std, libc)]
+# #![feature(libc)]
+#![feature(lang_items)]
+#![feature(start)]
+#![feature(no_std)]
#![no_std]
// Pull in the system libc library for what crt0.o likely requires
correct ABI and the correct name, which requires overriding the
compiler's name mangling too:
-```ignore
+```rust
+# #![feature(libc)]
#![feature(no_std)]
+#![feature(lang_items)]
+#![feature(start)]
#![no_std]
#![no_main]
-#![feature(lang_items, start)]
extern crate libc;
The core library has very few dependencies and is much more portable than the
standard library itself. Additionally, the core library has most of the
-necessary functionality for writing idiomatic and effective Rust code.
+necessary functionality for writing idiomatic and effective Rust code. When
+using `#![no_std]`, Rust will automatically inject the `core` crate, just like
+we do for `std` when we’re using it.
As an example, here is a program that will calculate the dot product of two
vectors provided from C, using idiomatic Rust practices.
-```ignore
-#![feature(lang_items, start, no_std, core, libc)]
+```rust
+# #![feature(libc)]
+#![feature(lang_items)]
+#![feature(start)]
+#![feature(no_std)]
+#![feature(core)]
+#![feature(core_slice_ext)]
+#![feature(raw)]
#![no_std]
-# extern crate libc;
-extern crate core;
-
-use core::prelude::*;
+extern crate libc;
use core::mem;
# Ownership
[Variable bindings][bindings] have a property in Rust: they ‘have ownership’
-of what they’re bound to. This means that when a binding goes out of scope,
+of what they’re bound to. This means that when a binding goes out of scope,
Rust will free the bound resources. For example:
```rust
All primitive types implement the `Copy` trait and their ownership is
therefore not moved like one would assume, following the ´ownership rules´.
-To give an example, the two following snippets of code only compile because the
-`i32` and `bool` types implement the `Copy` trait.
+To give an example, the two following snippets of code only compile because the
+`i32` and `bool` types implement the `Copy` trait.
```rust
fn main() {
Luckily, Rust offers a feature, borrowing, which helps us solve this problem.
It’s the topic of the next section!
-
-
-
-
-
-
-
-
-
-
This prints `one`.
+There’s one pitfall with patterns: like anything that introduces a new binding,
+they introduce shadowing. For example:
+
+```rust
+let x = 'x';
+let c = 'c';
+
+match c {
+ x => println!("x: {} c: {}", x, c),
+}
+
+println!("x: {}", x)
+```
+
+This prints:
+
+```text
+x: c c: c
+x: x
+```
+
+In other words, `x =>` matches the pattern and introduces a new binding named
+`x` that’s in scope for the match arm. Because we already have a binding named
+`x`, this new `x` shadows it.
+
# Multiple patterns
You can match multiple patterns with `|`:
```
This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
-just the `5`, In other words, the the precedence of `if` behaves like this:
+just the `5`. In other words, the precedence of `if` behaves like this:
```text
(4 | 5) if y => ...
useful for allowing safe, efficient access to a portion of an array without
copying. For example, you might want to reference just one line of a file read
into memory. By nature, a slice is not created directly, but from an existing
-variable. Slices have a length, can be mutable or not, and in many ways behave
-like arrays:
+variable binding. Slices have a defined length, can be mutable or immutable.
+
+## Slicing syntax
+
+You can use a combo of `&` and `[]` to create a slice from various things. The
+`&` indicates that slices are similar to references, and the `[]`s, with a
+range, let you define the length of the slice:
```rust
let a = [0, 1, 2, 3, 4];
-let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
let complete = &a[..]; // A slice containing all of the elements in a
+let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
```
Slices have type `&[T]`. We’ll talk about that `T` when we cover
and so any conversion from raw pointers is asserting that they hold. The
programmer *must* guarantee this.
-The recommended method for the conversion is
+The recommended method for the conversion is:
```rust
-let i: u32 = 1;
-
// explicit cast
+let i: u32 = 1;
let p_imm: *const u32 = &i as *const u32;
-let mut m: u32 = 2;
// implicit coercion
+let mut m: u32 = 2;
let p_mut: *mut u32 = &mut m;
unsafe {
% References and Borrowing
-This guide is one of three presenting Rust’s ownership system. This is one of
+This guide is two of three presenting Rust’s ownership system. This is one of
Rust’s most unique and compelling features, with which Rust developers should
become quite acquainted. Ownership is how Rust achieves its largest goal,
memory safety. There are a few distinct concepts, each with its own
```rust
let mut x = 5;
-{
+{
let y = &mut x; // -+ &mut borrow starts here
*y += 1; // |
} // -+ ... and ends here
```rust,ignore
let y: &i32;
-{
+{
let x = 5;
y = &x;
}
note: reference must be valid for the block suffix following statement 0 at
2:16...
let y: &i32;
-{
+{
let x = 5;
y = &x;
}
let y: &i32;
let x = 5;
y = &x;
-
+
println!("{}", y);
}
statement 1 at 3:14
let x = 5;
y = &x;
-
+
println!("{}", y);
}
```
let handles: Vec<_> = (0..10).map(|_| {
thread::spawn(|| {
let mut x = 0;
- for _ in (0..5_000_000) {
+ for _ in 0..5_000_000 {
x += 1
}
x
println!("Thread finished with count={}",
h.join().map_err(|_| "Could not join a thread!").unwrap());
}
- println!("done!");
}
```
This prints:
```text
-229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172,
-忠, 犬, ハ, チ, 公,
+229, 191, 160, 231, 138, 172, 227, 131, 143, 227, 131, 129, 229, 133, 172,
+忠, 犬, ハ, チ, 公,
```
As you can see, there are more bytes than `char`s.
```rust
struct Electron;
+
+let x = Electron;
```
Such a `struct` is called ‘unit-like’ because it resembles the empty
--- /dev/null
+% Syntax Index
+
+## Keywords
+
+* `as`: primitive casting. See [Casting Between Types (`as`)].
+* `break`: break out of loop. See [Loops (Ending Iteration Early)].
+* `const`: constant items. See [`const` and `static`].
+* `continue`: continue to next loop iteration. See [Loops (Ending Iteration Early)].
+* `crate`: external crate linkage. See [Crates and Modules (Importing External Crates)].
+* `else`: fallback for `if` and `if let` constructs. See [`if`], [`if let`].
+* `enum`: defining enumeration. See [Enums].
+* `extern`: external crate, function, and variable linkage. See [Crates and Modules (Importing External Crates)], [Foreign Function Interface].
+* `false`: boolean false literal. See [Primitive Types (Booleans)].
+* `fn`: function definition and function pointer types. See [Functions].
+* `for`: iterator loop, part of trait `impl` syntax, and higher-ranked lifetime syntax. See [Loops (`for`)], [Method Syntax].
+* `if`: conditional branching. See [`if`], [`if let`].
+* `impl`: inherent and trait implementation blocks. See [Method Syntax].
+* `in`: part of `for` loop syntax. See [Loops (`for`)].
+* `let`: variable binding. See [Variable Bindings].
+* `loop`: unconditional, infinite loop. See [Loops (`loop`)].
+* `match`: pattern matching. See [Match].
+* `mod`: module declaration. See [Crates and Modules (Defining Modules)].
+* `move`: part of closure syntax. See [Closures (`move` closures)].
+* `mut`: denotes mutability in pointer types and pattern bindings. See [Mutability].
+* `pub`: denotes public visibility in `struct` fields, `impl` blocks, and modules. See [Crates and Modules (Exporting a Public Interface)].
+* `ref`: by-reference binding. See [Patterns (`ref` and `ref mut`)].
+* `return`: return from function. See [Functions (Early Returns)].
+* `Self`: implementor type alias. See [Traits].
+* `self`: method subject. See [Method Syntax (Method Calls)].
+* `static`: global variable. See [`const` and `static` (`static`)].
+* `struct`: structure definition. See [Structs].
+* `trait`: trait definition. See [Traits].
+* `true`: boolean true literal. See [Primitive Types (Booleans)].
+* `type`: type alias, and associated type definition. See [`type` Aliases], [Associated Types].
+* `unsafe`: denotes unsafe code, functions, traits, and implementations. See [Unsafe].
+* `use`: import symbols into scope. See [Crates and Modules (Importing Modules with `use`)].
+* `where`: type constraint clauses. See [Traits (`where` clause)].
+* `while`: conditional loop. See [Loops (`while`)].
+
+## Operators and Symbols
+
+* `!` (`expr!(…)`, `expr!{…}`, `expr![…]`): denotes macro expansion. See [Macros].
+* `!` (`!expr`): bitwise or logical complement. Overloadable (`Not`).
+* `%` (`expr % expr`): arithmetic remainder. Overloadable (`Rem`).
+* `%=` (`var %= expr`): arithmetic remainder & assignment.
+* `&` (`expr & expr`): bitwise and. Overloadable (`BitAnd`).
+* `&` (`&expr`): borrow. See [References and Borrowing].
+* `&` (`&type`, `&mut type`, `&'a type`, `&'a mut type`): borrowed pointer type. See [References and Borrowing].
+* `&=` (`var &= expr`): bitwise and & assignment.
+* `&&` (`expr && expr`): logical and.
+* `*` (`expr * expr`): arithmetic multiplication. Overloadable (`Mul`).
+* `*` (`*expr`): dereference.
+* `*` (`*const type`, `*mut type`): raw pointer. See [Raw Pointers].
+* `*=` (`var *= expr`): arithmetic multiplication & assignment.
+* `+` (`expr + expr`): arithmetic addition. Overloadable (`Add`).
+* `+` (`trait + trait`, `'a + trait`): compound type constraint. See [Traits (Multiple Trait Bounds)].
+* `+=` (`var += expr`): arithmetic addition & assignment.
+* `,`: argument and element separator. See [Attributes], [Functions], [Structs], [Generics], [Match], [Closures], [Crates and Modules (Importing Modules with `use`)].
+* `-` (`expr - expr`): arithmetic subtraction. Overloadable (`Sub`).
+* `-` (`- expr`): arithmetic negation. Overloadable (`Neg`).
+* `-=` (`var -= expr`): arithmetic subtraction & assignment.
+* `->` (`fn(…) -> type`, `|…| -> type`): function and closure return type. See [Functions], [Closures].
+* `.` (`expr.ident`): member access. See [Structs], [Method Syntax].
+* `..` (`..`, `expr..`, `..expr`, `expr..expr`): right-exclusive range literal.
+* `..` (`..expr`): struct literal update syntax. See [Structs (Update syntax)].
+* `..` (`variant(x, ..)`, `struct_type { x, .. }`): "and the rest" pattern binding. See [Patterns (Ignoring bindings)].
+* `...` (`expr ... expr`): inclusive range pattern. See [Patterns (Ranges)].
+* `/` (`expr / expr`): arithmetic division. Overloadable (`Div`).
+* `/=` (`var /= expr`): arithmetic division & assignment.
+* `:` (`pat: type`, `ident: type`): constraints. See [Variable Bindings], [Functions], [Structs], [Traits].
+* `:` (`ident: expr`): struct field initializer. See [Structs].
+* `:` (`'a: loop {…}`): loop label. See [Loops (Loops Labels)].
+* `;`: statement and item terminator.
+* `;` (`[…; len]`): part of fixed-size array syntax. See [Primitive Types (Arrays)].
+* `<<` (`expr << expr`): left-shift. Overloadable (`Shl`).
+* `<<=` (`var <<= expr`): left-shift & assignment.
+* `<` (`expr < expr`): less-than comparison. Overloadable (`Cmp`, `PartialCmp`).
+* `<=` (`var <= expr`): less-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`).
+* `=` (`var = expr`, `ident = type`): assignment/equivalence. See [Variable Bindings], [`type` Aliases], generic parameter defaults.
+* `==` (`var == expr`): comparison. Overloadable (`Eq`, `PartialEq`).
+* `=>` (`pat => expr`): part of match arm syntax. See [Match].
+* `>` (`expr > expr`): greater-than comparison. Overloadable (`Cmp`, `PartialCmp`).
+* `>=` (`var >= expr`): greater-than or equal-to comparison. Overloadable (`Cmp`, `PartialCmp`).
+* `>>` (`expr >> expr`): right-shift. Overloadable (`Shr`).
+* `>>=` (`var >>= expr`): right-shift & assignment.
+* `@` (`ident @ pat`): pattern binding. See [Patterns (Bindings)].
+* `^` (`expr ^ expr`): bitwise exclusive or. Overloadable (`BitXor`).
+* `^=` (`var ^= expr`): bitwise exclusive or & assignment.
+* `|` (`expr | expr`): bitwise or. Overloadable (`BitOr`).
+* `|` (`pat | pat`): pattern alternatives. See [Patterns (Multiple patterns)].
+* `|=` (`var |= expr`): bitwise or & assignment.
+* `||` (`expr || expr`): logical or.
+* `_`: "ignored" pattern binding. See [Patterns (Ignoring bindings)].
+
+## Other Syntax
+
+<!-- Various bits of standalone stuff. -->
+
+* `'ident`: named lifetime or loop label. See [Lifetimes], [Loops (Loops Labels)].
+* `…u8`, `…i32`, `…f64`, `…usize`, …: numeric literal of specific type.
+* `"…"`: string literal. See [Strings].
+* `r"…"`, `r#"…"#`, `r##"…"##`, …: raw string literal.
+* `b"…"`: byte string literal.
+* `rb"…"`, `rb#"…"#`, `rb##"…"##`, …: raw byte string literal.
+* `'…'`: character literal. See [Primitive Types (`char`)].
+* `b'…'`: ASCII byte literal.
+
+<!-- Path-related syntax -->
+
+* `ident::ident`: path. See [Crates and Modules (Defining Modules)].
+* `::path`: path relative to the crate root (*i.e.* an explicitly absolute path). See [Crates and Modules (Re-exporting with `pub use`)].
+* `self::path`: path relative to the current module (*i.e.* an explicitly relative path). See [Crates and Modules (Re-exporting with `pub use`)].
+* `super::path`: path relative to the parent of the current module. See [Crates and Modules (Re-exporting with `pub use`)].
+* `type::ident`: associated constants, functions, and types. See [Associated Types].
+* `<type>::…`: associated item for a type which cannot be directly named (*e.g.* `<&T>::…`, `<[T]>::…`, *etc.*). See [Associated Types].
+
+<!-- Generics -->
+
+* `path<…>` (*e.g.* `Vec<u8>`): specifies parameters to generic type *in a type*. See [Generics].
+* `path::<…>`, `method::<…>` (*e.g.* `"42".parse::<i32>()`): specifies parameters to generic type, function, or method *in an expression*.
+* `fn ident<…> …`: define generic function. See [Generics].
+* `struct ident<…> …`: define generic structure. See [Generics].
+* `enum ident<…> …`: define generic enumeration. See [Generics].
+* `impl<…> …`: define generic implementation.
+* `for<…> type`: higher-ranked lifetime bounds.
+* `type<ident=type>` (*e.g.* `Iterator<Item=T>`): a generic type where one or more associated types have specific assignments. See [Associated Types].
+
+<!-- Constraints -->
+
+* `T: U`: generic parameter `T` constrained to types that implement `U`. See [Traits].
+* `T: 'a`: generic type `T` must outlive lifetime `'a`.
+* `'b: 'a`: generic lifetime `'b` must outlive lifetime `'a`.
+* `T: ?Sized`: allow generic type parameter to be a dynamically-sized type. See [Unsized Types (`?Sized`)].
+* `'a + trait`, `trait + trait`: compound type constraint. See [Traits (Multiple Trait Bounds)].
+
+<!-- Macros and attributes -->
+
+* `#[meta]`: outer attribute. See [Attributes].
+* `#![meta]`: inner attribute. See [Attributes].
+* `$ident`: macro substitution. See [Macros].
+* `$ident:kind`: macro capture. See [Macros].
+* `$(…)…`: macro repetition. See [Macros].
+
+<!-- Comments -->
+
+* `//`: line comment. See [Comments].
+* `//!`: inner line doc comment. See [Comments].
+* `///`: outer line doc comment. See [Comments].
+* `/*…*/`: block comment. See [Comments].
+* `/*!…*/`: inner block doc comment. See [Comments].
+* `/**…*/`: outer block doc comment. See [Comments].
+
+<!-- Various things involving parens and tuples -->
+
+* `()`: empty tuple (*a.k.a.* unit), both literal and type.
+* `(expr)`: parenthesized expression.
+* `(expr,)`: single-element tuple expression. See [Primitive Types (Tuples)].
+* `(type,)`: single-element tuple type. See [Primitive Types (Tuples)].
+* `(expr, …)`: tuple expression. See [Primitive Types (Tuples)].
+* `(type, …)`: tuple type. See [Primitive Types (Tuples)].
+* `expr(expr, …)`: function call expression. Also used to initialize tuple `struct`s and tuple `enum` variants. See [Functions].
+* `ident!(…)`, `ident!{…}`, `ident![…]`: macro invocation. See [Macros].
+* `expr.0`, `expr.1`, …: tuple indexing. See [Primitive Types (Tuple Indexing)].
+
+<!-- Bracey things -->
+
+* `{…}`: block expression.
+* `Type {…}`: `struct` literal. See [Structs].
+
+<!-- Brackety things -->
+
+* `[…]`: array literal. See [Primitive Types (Arrays)].
+* `[expr; len]`: array literal containing `len` copies of `expr`. See [Primitive Types (Arrays)].
+* `[type; len]`: array type containing `len` instances of `type`. See [Primitive Types (Arrays)].
+
+[`const` and `static` (`static`)]: const-and-static.html#static
+[`const` and `static`]: const-and-static.html
+[`if let`]: if-let.html
+[`if`]: if.html
+[`type` Aliases]: type-aliases.html
+[Associated Types]: associated-types.html
+[Attributes]: attributes.html
+[Casting Between Types (`as`)]: casting-between-types.html#as
+[Closures (`move` closures)]: closures.html#move-closures
+[Closures]: closures.html
+[Comments]: comments.html
+[Crates and Modules (Defining Modules)]: crates-and-modules.html#defining-modules
+[Crates and Modules (Exporting a Public Interface)]: crates-and-modules.html#exporting-a-public-interface
+[Crates and Modules (Importing External Crates)]: crates-and-modules.html#importing-external-crates
+[Crates and Modules (Importing Modules with `use`)]: crates-and-modules.html#importing-modules-with-use
+[Crates and Modules (Re-exporting with `pub use`)]: crates-and-modules.html#re-exporting-with-pub-use
+[Enums]: enums.html
+[Foreign Function Interface]: ffi.html
+[Functions (Early Returns)]: functions.html#early-returns
+[Functions]: functions.html
+[Generics]: generics.html
+[Lifetimes]: lifetimes.html
+[Loops (`for`)]: loops.html#for
+[Loops (`loop`)]: loops.html#loop
+[Loops (`while`)]: loops.html#while
+[Loops (Ending Iteration Early)]: loops.html#ending-iteration-early
+[Loops (Loops Labels)]: loops.html#loop-labels
+[Macros]: macros.html
+[Match]: match.html
+[Method Syntax (Method Calls)]: method-syntax.html#method-calls
+[Method Syntax]: method-syntax.html
+[Mutability]: mutability.html
+[Operators and Overloading]: operators-and-overloading.html
+[Patterns (`ref` and `ref mut`)]: patterns.html#ref-and-ref-mut
+[Patterns (Bindings)]: patterns.html#bindings
+[Patterns (Ignoring bindings)]: patterns.html#ignoring-bindings
+[Patterns (Multiple patterns)]: patterns.html#multiple-patterns
+[Patterns (Ranges)]: patterns.html#ranges
+[Primitive Types (`char`)]: primitive-types.html#char
+[Primitive Types (Arrays)]: primitive-types.html#arrays
+[Primitive Types (Booleans)]: primitive-types.html#booleans
+[Primitive Types (Tuple Indexing)]: primitive-types.html#tuple-indexing
+[Primitive Types (Tuples)]: primitive-types.html#tuples
+[Raw Pointers]: raw-pointers.html
+[References and Borrowing]: references-and-borrowing.html
+[Strings]: strings.html
+[Structs (Update syntax)]: structs.html#update-syntax
+[Structs]: structs.html
+[Traits (`where` clause)]: traits.html#where-clause
+[Traits (Multiple Trait Bounds)]: traits.html#multiple-trait-bounds
+[Traits]: traits.html
+[Unsafe]: unsafe.html
+[Unsized Types (`?Sized`)]: unsized-types.html#?sized
+[Variable Bindings]: variable-bindings.html
```
`assert!` is a macro provided by Rust which takes one argument: if the argument
-is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run
+is `true`, nothing happens. If the argument is `false`, it `panic!`s. Let's run
our tests again:
```bash
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
```
-The `--ignored` argument is an argument to the test binary, and not to cargo,
+The `--ignored` argument is an argument to the test binary, and not to Cargo,
which is why the command is `cargo test -- --ignored`.
# The `tests` module
The current convention is to use the `tests` module to hold your "unit-style"
tests. Anything that just tests one small bit of functionality makes sense to
go here. But what about "integration-style" tests instead? For that, we have
-the `tests` directory
+the `tests` directory.
# The `tests` directory
for the function test. These will auto increment with names like `add_two_1` as
you add more examples.
+We haven’t covered all of the details with writing documentation tests. For more,
+please see the [Documentation chapter](documentation.html)
+
+One final note: Tests *cannot* be run on a binary file. To see more on file arrangement see the [Crates and Modules](crates-and-modules.html) section.
+
This is automatically handled for you, as you can see; we didn’t have to write
any special Rust code or anything.
-When the function is over, its stack frame gets deallocated. This happens
-automatically, we didn’t have to do anything special here.
+When the function exits, its stack frame gets deallocated. This happens
+automatically as well.
That’s all there is for this simple program. The key thing to understand here
is that stack allocation is very, very fast. Since we know all the local
it allocates some memory for the heap, and puts `5` there. The memory now looks
like this:
-| Address | Name | Value |
-|-----------------|------|------------------|
-| 2<sup>30</sup> | | 5 |
-| ... | ... | ... |
-| 1 | y | 42 |
-| 0 | x | → 2<sup>30</sup> |
+| Address | Name | Value |
+|----------------------|------|------------------------|
+| (2<sup>30</sup>) - 1 | | 5 |
+| ... | ... | ... |
+| 1 | y | 42 |
+| 0 | x | → (2<sup>30</sup>) - 1 |
-We have 2<sup>30</sup> in our hypothetical computer with 1GB of RAM. And since
+We have (2<sup>30</sup>) - 1 addresses in our hypothetical computer with 1GB of RAM. And since
our stack grows from zero, the easiest place to allocate memory is from the
other end. So our first value is at the highest place in memory. And the value
of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve
-allocated on the heap, so the value of `x` is 2<sup>30</sup>, the memory
+allocated on the heap, so the value of `x` is (2<sup>30</sup>) - 1, the memory
location we’ve asked for.
[rawpointer]: raw-pointers.html
| Address | Name | Value |
|----------------------|------|------------------------|
-| 2<sup>30</sup> | | 5 |
-| (2<sup>30</sup>) - 1 | | |
+| (2<sup>30</sup>) - 1 | | 5 |
| (2<sup>30</sup>) - 2 | | |
-| (2<sup>30</sup>) - 3 | | 42 |
+| (2<sup>30</sup>) - 3 | | |
+| (2<sup>30</sup>) - 4 | | 42 |
| ... | ... | ... |
-| 3 | y | → (2<sup>30</sup>) - 3 |
+| 3 | y | → (2<sup>30</sup>) - 4 |
| 2 | y | 42 |
| 1 | y | 42 |
-| 0 | x | → 2<sup>30</sup> |
+| 0 | x | → (2<sup>30</sup>) - 1 |
In this case, we’ve allocated four things on the heap, but deallocated two of
-them. There’s a gap between 2<sup>30</sup> and (2<sup>30</sup>) - 3 which isn’t
+them. There’s a gap between (2<sup>30</sup>) - 1 and (2<sup>30</sup>) - 4 which isn’t
currently being used. The specific details of how and why this happens depends
on what kind of strategy you use to manage the heap. Different programs can use
different ‘memory allocators’, which are libraries that manage this for you.
First, we call `main()`:
-| Address | Name | Value |
-|-----------------|------|------------------|
-| 2<sup>30</sup> | | 20 |
-| ... | ... | ... |
-| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
-| 0 | h | 3 |
+| Address | Name | Value |
+|----------------------|------|------------------------|
+| (2<sup>30</sup>) - 1 | | 20 |
+| ... | ... | ... |
+| 2 | j | → 0 |
+| 1 | i | → (2<sup>30</sup>) - 1 |
+| 0 | h | 3 |
We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a
value pointing there.
Next, at the end of `main()`, `foo()` gets called:
-| Address | Name | Value |
-|-----------------|------|-----------------|
-| 2<sup>30</sup> | | 20 |
-| ... | ... | ... |
-| 5 | z | → 4 |
-| 4 | y | 10 |
-| 3 | x | → 0 |
-| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup>|
-| 0 | h | 3 |
+| Address | Name | Value |
+|----------------------|------|------------------------|
+| (2<sup>30</sup>) - 1 | | 20 |
+| ... | ... | ... |
+| 5 | z | → 4 |
+| 4 | y | 10 |
+| 3 | x | → 0 |
+| 2 | j | → 0 |
+| 1 | i | → (2<sup>30</sup>) - 1 |
+| 0 | h | 3 |
Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value
as `j`, since that’s what we passed it in. It’s a pointer to the `0` address,
Next, `foo()` calls `baz()`, passing `z`:
-| Address | Name | Value |
-|-----------------|------|------------------|
-| 2<sup>30</sup> | | 20 |
-| ... | ... | ... |
-| 7 | g | 100 |
-| 6 | f | → 4 |
-| 5 | z | → 4 |
-| 4 | y | 10 |
-| 3 | x | → 0 |
-| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
-| 0 | h | 3 |
+| Address | Name | Value |
+|----------------------|------|------------------------|
+| (2<sup>30</sup>) - 1 | | 20 |
+| ... | ... | ... |
+| 7 | g | 100 |
+| 6 | f | → 4 |
+| 5 | z | → 4 |
+| 4 | y | 10 |
+| 3 | x | → 0 |
+| 2 | j | → 0 |
+| 1 | i | → (2<sup>30</sup>) - 1 |
+| 0 | h | 3 |
We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s
over, we get rid of its stack frame:
-| Address | Name | Value |
-|-----------------|------|------------------|
-| 2<sup>30</sup> | | 20 |
-| ... | ... | ... |
-| 5 | z | → 4 |
-| 4 | y | 10 |
-| 3 | x | → 0 |
-| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
-| 0 | h | 3 |
+| Address | Name | Value |
+|----------------------|------|------------------------|
+| (2<sup>30</sup>) - 1 | | 20 |
+| ... | ... | ... |
+| 5 | z | → 4 |
+| 4 | y | 10 |
+| 3 | x | → 0 |
+| 2 | j | → 0 |
+| 1 | i | → (2<sup>30</sup>) - 1 |
+| 0 | h | 3 |
Next, `foo()` calls `bar()` with `x` and `z`:
| Address | Name | Value |
|----------------------|------|------------------------|
-| 2<sup>30</sup> | | 20 |
-| (2<sup>30</sup>) - 1 | | 5 |
+| (2<sup>30</sup>) - 1 | | 20 |
+| (2<sup>30</sup>) - 2 | | 5 |
| ... | ... | ... |
| 10 | e | → 9 |
-| 9 | d | → (2<sup>30</sup>) - 1 |
+| 9 | d | → (2<sup>30</sup>) - 2 |
| 8 | c | 5 |
| 7 | b | → 4 |
| 6 | a | → 0 |
| 4 | y | 10 |
| 3 | x | → 0 |
| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
+| 1 | i | → (2<sup>30</sup>) - 1 |
| 0 | h | 3 |
We end up allocating another value on the heap, and so we have to subtract one
-from 2<sup>30</sup>. It’s easier to just write that than `1,073,741,823`. In any
+from (2<sup>30</sup>) - 1. It’s easier to just write that than `1,073,741,822`. In any
case, we set up the variables as usual.
At the end of `bar()`, it calls `baz()`:
| Address | Name | Value |
|----------------------|------|------------------------|
-| 2<sup>30</sup> | | 20 |
-| (2<sup>30</sup>) - 1 | | 5 |
+| (2<sup>30</sup>) - 1 | | 20 |
+| (2<sup>30</sup>) - 2 | | 5 |
| ... | ... | ... |
| 12 | g | 100 |
| 11 | f | → 9 |
| 10 | e | → 9 |
-| 9 | d | → (2<sup>30</sup>) - 1 |
+| 9 | d | → (2<sup>30</sup>) - 2 |
| 8 | c | 5 |
| 7 | b | → 4 |
| 6 | a | → 0 |
| 4 | y | 10 |
| 3 | x | → 0 |
| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
+| 1 | i | → (2<sup>30</sup>) - 1 |
| 0 | h | 3 |
With this, we’re at our deepest point! Whew! Congrats for following along this
| Address | Name | Value |
|----------------------|------|------------------------|
-| 2<sup>30</sup> | | 20 |
-| (2<sup>30</sup>) - 1 | | 5 |
+| (2<sup>30</sup>) - 1 | | 20 |
+| (2<sup>30</sup>) - 2 | | 5 |
| ... | ... | ... |
| 10 | e | → 9 |
-| 9 | d | → (2<sup>30</sup>) - 1 |
+| 9 | d | → (2<sup>30</sup>) - 2 |
| 8 | c | 5 |
| 7 | b | → 4 |
| 6 | a | → 0 |
| 4 | y | 10 |
| 3 | x | → 0 |
| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
+| 1 | i | → (2<sup>30</sup>) - 1 |
| 0 | h | 3 |
Next, we return from `bar()`. `d` in this case is a `Box<T>`, so it also frees
-what it points to: (2<sup>30</sup>) - 1.
-
-| Address | Name | Value |
-|-----------------|------|------------------|
-| 2<sup>30</sup> | | 20 |
-| ... | ... | ... |
-| 5 | z | → 4 |
-| 4 | y | 10 |
-| 3 | x | → 0 |
-| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
-| 0 | h | 3 |
+what it points to: (2<sup>30</sup>) - 2.
+
+| Address | Name | Value |
+|----------------------|------|------------------------|
+| (2<sup>30</sup>) - 1 | | 20 |
+| ... | ... | ... |
+| 5 | z | → 4 |
+| 4 | y | 10 |
+| 3 | x | → 0 |
+| 2 | j | → 0 |
+| 1 | i | → (2<sup>30</sup>) - 1 |
+| 0 | h | 3 |
And after that, `foo()` returns:
-| Address | Name | Value |
-|-----------------|------|------------------|
-| 2<sup>30</sup> | | 20 |
-| ... | ... | ... |
-| 2 | j | → 0 |
-| 1 | i | → 2<sup>30</sup> |
-| 0 | h | 3 |
+| Address | Name | Value |
+|----------------------|------|------------------------|
+| (2<sup>30</sup>) - 1 | | 20 |
+| ... | ... | ... |
+| 2 | j | → 0 |
+| 1 | i | → (2<sup>30</sup>) - 1 |
+| 0 | h | 3 |
And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped,
it will clean up the last of the heap too.
but we don’t define a body, just a type signature. When we `impl` a trait,
we use `impl Trait for Item`, rather than just `impl Item`.
-## Traits bounds for generic functions
+## Trait bounds on generic functions
Traits are useful because they allow a type to make certain promises about its
-behavior. Generic functions can exploit this to constrain the types they
+behavior. Generic functions can exploit this to constrain, or [bound][bounds], the types they
accept. Consider this function, which does not compile:
+[bounds]: glossary.html#bounds
+
```rust,ignore
fn print_area<T>(shape: T) {
println!("This shape has an area of {}", shape.area());
```
Because `T` can be any type, we can’t be sure that it implements the `area`
-method. But we can add a ‘trait constraint’ to our generic `T`, ensuring
+method. But we can add a trait bound to our generic `T`, ensuring
that it does:
```rust
error: the trait `HasArea` is not implemented for the type `_` [E0277]
```
-## Traits bounds for generic structs
+## Trait bounds on generic structs
-Your generic structs can also benefit from trait constraints. All you need to
-do is append the constraint when you declare type parameters. Here is a new
+Your generic structs can also benefit from trait bounds. All you need to
+do is append the bound when you declare type parameters. Here is a new
type `Rectangle<T>` and its operation `is_square()`:
```rust
```text
error: the trait `main::Foo` is not implemented for the type `main::Baz` [E0277]
```
+
+# Deriving
+
+Implementing traits like `Debug` and `Default` over and over again can become
+quite tedious. For that reason, Rust provides an [attribute][attributes] that
+allows you to let Rust automatically implement traits for you:
+
+```rust
+#[derive(Debug)]
+struct Foo;
+
+fn main() {
+ println!("{:?}", Foo);
+}
+```
+
+[attributes]: attributes.html
+
+However, deriving is limited to a certain set of traits:
+
+- [`Clone`](../core/clone/trait.Clone.html)
+- [`Copy`](../core/marker/trait.Copy.html)
+- [`Debug`](../core/fmt/trait.Debug.html)
+- [`Default`](../core/default/trait.Default.html)
+- [`Eq`](../core/cmp/trait.Eq.html)
+- [`Hash`](../core/hash/trait.Hash.html)
+- [`Ord`](../core/cmp/trait.Ord.html)
+- [`PartialEq`](../core/cmp/trait.PartialEq.html)
+- [`PartialOrd`](../core/cmp/trait.PartialOrd.html)
% Variable Bindings
Virtually every non-'Hello World’ Rust program uses *variable bindings*. They
-look like this:
+bind some value to a name, so it can be used later. `let` is
+used to introduce a binding, just like this:
```rust
fn main() {
in the future. If you’re following along, make sure to edit your `main()`
function, rather than leaving it off. Otherwise, you’ll get an error.
-In many languages, this is called a *variable*, but Rust’s variable bindings
-have a few tricks up their sleeves. For example the left-hand side of a `let`
-expression is a ‘[pattern][pattern]’, not just a variable name. This means we
-can do things like:
+# Patterns
+
+In many languages, a variable binding would be called a *variable*, but Rust’s
+variable bindings have a few tricks up their sleeves. For example the
+left-hand side of a `let` expression is a ‘[pattern][pattern]’, not just a
+variable name. This means we can do things like:
```rust
let (x, y) = (1, 2);
[pattern]: patterns.html
+# Type annotations
+
Rust is a statically typed language, which means that we specify our types up
front, and they’re checked at compile time. So why does our first example
compile? Well, Rust has this thing called ‘type inference’. If it can figure
occasionally include them to help you understand what the types that Rust
infers are.
+# Mutability
+
By default, bindings are *immutable*. This code will not compile:
```rust,ignore
mutation, and so it is preferable in Rust. That said, sometimes, mutation is
what you need, so it’s not verboten.
-Let’s get back to bindings. Rust variable bindings have one more aspect that
-differs from other languages: bindings are required to be initialized with a
-value before you're allowed to use them.
+# Initializing bindings
+
+Rust variable bindings have one more aspect that differs from other languages:
+bindings are required to be initialized with a value before you're allowed to
+use them.
Let’s try it out. Change your `src/main.rs` file to look like this:
print.
[format]: ../std/fmt/index.html
+
+# Scope and shadowing
+
+Let’s get back to bindings. Variable bindings have a scope - they are
+constrained to live in a block they were defined in. A block is a collection
+of statements enclosed by `{` and `}`. Function definitions are also blocks!
+In the following example we define two variable bindings, `x` and `y`, which
+live in different blocks. `x` can be accessed from inside the `fn main() {}`
+block, while `y` can be accessed only from inside the inner block:
+
+```rust,ignore
+fn main() {
+ let x: i32 = 17;
+ {
+ let y: i32 = 3;
+ println!("The value of x is {} and value of y is {}", x, y);
+ }
+ println!("The value of x is {} and value of y is {}", x, y); // This won't work
+}
+```
+
+The first `println!` would print "The value of x is 17 and the value of y is
+3", but this example cannot be compiled successfully, because the second
+`println!` cannot access the value of `y`, since it is not in scope anymore.
+Instead we get this error:
+
+```bash
+$ cargo build
+ Compiling hello v0.1.0 (file:///home/you/projects/hello_world)
+main.rs:7:62: 7:63 error: unresolved name `y`. Did you mean `x`? [E0425]
+main.rs:7 println!("The value of x is {} and value of y is {}", x, y); // This won't work
+ ^
+note: in expansion of format_args!
+<std macros>:2:25: 2:56 note: expansion site
+<std macros>:1:1: 2:62 note: in expansion of print!
+<std macros>:3:1: 3:54 note: expansion site
+<std macros>:1:1: 3:58 note: in expansion of println!
+main.rs:7:5: 7:65 note: expansion site
+main.rs:7:62: 7:63 help: run `rustc --explain E0425` to see a detailed explanation
+error: aborting due to previous error
+Could not compile `hello`.
+
+To learn more, run the command again with --verbose.
+```
+
+Additionally, variable bindings can be shadowed. This means that a later
+variable binding with the same name as another binding, that's currently in
+scope, will override the previous binding.
+
+```rust
+let x: i32 = 8;
+{
+ println!("{}", x); // Prints "8"
+ let x = 12;
+ println!("{}", x); // Prints "12"
+}
+println!("{}", x); // Prints "8"
+let x = 42;
+println!("{}", x); // Prints "42"
+```
+
+Shadowing and mutable bindings may appear as two sides of the same coin, but
+they are two distinct concepts that can't always be used interchangeably. For
+one, shadowing enables us to rebind a name to a value of a different type. It
+is also possible to change the mutability of a binding.
+
+```rust
+let mut x: i32 = 1;
+x = 7;
+let x = x; // x is now immutable and is bound to 7
+
+let y = 4;
+let y = "I can also be bound to text!"; // y is now of a different type
+```
The indices count from `0`, so the third element is `v[2]`.
+It’s also important to note that you must index with the `usize` type:
+
+```ignore
+let v = vec![1, 2, 3, 4, 5];
+
+let i: usize = 0;
+let j: i32 = 0;
+
+// works
+v[i];
+
+// doesn’t
+v[j];
+```
+
+Indexing with a non-`usize` type gives an error that looks like this:
+
+```text
+error: the trait `core::ops::Index<i32>` is not implemented for the type
+`collections::vec::Vec<_>` [E0277]
+v[j];
+^~~~
+note: the type `collections::vec::Vec<_>` cannot be indexed by `i32`
+error: aborting due to previous error
+```
+
+There’s a lot of punctuation in that message, but the core of it makes sense:
+you cannot index with an `i32`.
+
## Iterating
Once you have a vector, you can iterate through its elements with `for`. There
#[cfg(rustc)]
extern crate rustc_driver as this;
-fn main() { this::main() }
+fn main() {
+ this::main()
+}
let path = try!(entry).path();
let mut metadata_str = String::new();
- try!(
- File::open(&path).and_then(|mut f|
- f.read_to_string(&mut metadata_str))
- );
+ try!(File::open(&path).and_then(|mut f| f.read_to_string(&mut metadata_str)));
let some_errors: ErrorMetadataMap = try!(json::decode(&metadata_str));
// Enclose each error in a div so they can be shown/hidden en masse.
let desc_desc = match info.description {
Some(_) => "error-described",
- None => "error-undescribed"
+ None => "error-undescribed",
};
let use_desc = match info.use_site {
Some(_) => "error-used",
- None => "error-unused"
+ None => "error-unused",
};
try!(write!(&mut output_file, "<div class=\"{} {}\">", desc_desc, use_desc));
// Error title (with self-link).
try!(write!(&mut output_file,
- "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
- err_code
- ));
+ "<h2 id=\"{0}\" class=\"section-header\"><a href=\"#{0}\">{0}</a></h2>\n",
+ err_code));
// Description rendered as markdown.
match info.description {
Some(ref desc) => try!(write!(&mut output_file, "{}", Markdown(desc))),
- None => try!(write!(&mut output_file, "<p>No description.</p>\n"))
+ None => try!(write!(&mut output_file, "<p>No description.</p>\n")),
}
try!(write!(&mut output_file, "</div>\n"));
('PartialOrd', ['PartialEq'], 8),
('Eq', ['PartialEq'], 1),
('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1),
- ('Show', [], 1),
+ ('Debug', [], 1),
('Hash', [], 1)]:
traits[trait] = (ALL, supers, errs)
import os
import sys
+target_triple = sys.argv[14]
def normalize_path(v):
"""msys1/msys2 automatically converts `/abs/path1:/abs/path2` into
windows paths so it is really error-prone. revert it for peace."""
v = v.replace('\\', '/')
# c:/path -> /c/path
- if ':/' in v:
- v = '/' + v.replace(':/', '/')
+ # "c:/path" -> "/c/path"
+ start = v.find(':/')
+ while start != -1:
+ v = v[:start - 1] + '/' + v[start - 1:start] + v[start + 1:]
+ start = v.find(':/')
return v
putenv('RUST_BUILD_STAGE', sys.argv[12])
putenv('S', os.path.abspath(sys.argv[13]))
putenv('PYTHON', sys.executable)
+os.putenv('TARGET', target_triple)
+
+if 'msvc' in target_triple:
+ os.putenv('IS_MSVC', '1')
if filt not in sys.argv[1]:
sys.exit(0)
components = sys.argv[2].split() # splits on whitespace
enable_static = sys.argv[3]
llvm_config = sys.argv[4]
+stdcpp_name = sys.argv[5]
f.write("""// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
out = run([llvm_config, '--cxxflags'])
if enable_static == '1':
assert('stdlib=libc++' not in out)
- f.write("#[link(name = \"stdc++\", kind = \"static\")]\n")
+ f.write("#[link(name = \"" + stdcpp_name + "\", kind = \"static\")]\n")
else:
# Note that we use `cfg_attr` here because on MSVC the C++ standard library
# is not c++ or stdc++, but rather the linker takes care of linking the
if 'stdlib=libc++' in out:
f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"c++\"))]\n")
else:
- f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"stdc++\"))]\n")
+ f.write("#[cfg_attr(not(target_env = \"msvc\"), link(name = \"" + stdcpp_name + "\"))]\n")
# Attach everything to an extern block
f.write("extern {}\n")
Incomplete records are an error. Not-a-Number bit patterns are invalid too.
-The tests run serially but the validaition for a a single test is parallelized
+The tests run serially but the validation for a single test is parallelized
with ``multiprocessing``. Each test is launched as a subprocess.
One thread supervises it: Accepts and enqueues records to validate, observe
stderr, and waits for the process to exit. A set of worker processes perform
def emit_bsearch_range_table(f):
f.write("""
-fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool {
+fn bsearch_range_table(c: char, r: &'static [(char, char)]) -> bool {
use core::cmp::Ordering::{Equal, Less, Greater};
use core::slice::SliceExt;
- r.binary_search_by(|&(lo,hi)| {
- if lo <= c && c <= hi { Equal }
- else if hi < c { Less }
- else { Greater }
- }).is_ok()
+ r.binary_search_by(|&(lo, hi)| {
+ if lo <= c && c <= hi {
+ Equal
+ } else if hi < c {
+ Less
+ } else {
+ Greater
+ }
+ })
+ .is_ok()
}\n
""")
-0.12.0-13461-g8ab8581f6921bc7a8e3fa4defffd2814372dcb15
+0.12.0-14610-g3d7cd77e442ce34eaac8a176ae8be17669498ebc
use core::mem::{align_of_val, size_of_val};
use core::intrinsics::{drop_in_place, abort};
use core::mem;
-use core::nonzero::NonZero;
use core::ops::{Deref, CoerceUnsized};
-use core::ptr;
+use core::ptr::{self, Shared};
use core::marker::Unsize;
use core::hash::{Hash, Hasher};
use core::{usize, isize};
///
/// # Examples
///
-/// In this example, a large vector of floats is shared between several threads.
+/// In this example, a large vector is shared between several threads.
/// With simple pipes, without `Arc`, a copy would have to be made for each
/// thread.
///
pub struct Arc<T: ?Sized> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
- _ptr: NonZero<*mut ArcInner<T>>,
+ _ptr: Shared<ArcInner<T>>,
}
unsafe impl<T: ?Sized + Sync + Send> Send for Arc<T> { }
unsafe impl<T: ?Sized + Sync + Send> Sync for Arc<T> { }
+#[cfg(not(stage0))] // remove cfg after new snapshot
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
/// A weak pointer to an `Arc`.
pub struct Weak<T: ?Sized> {
// FIXME #12808: strange name to try to avoid interfering with
// field accesses of the contained type via Deref
- _ptr: NonZero<*mut ArcInner<T>>,
+ _ptr: Shared<ArcInner<T>>,
}
unsafe impl<T: ?Sized + Sync + Send> Send for Weak<T> { }
unsafe impl<T: ?Sized + Sync + Send> Sync for Weak<T> { }
+#[cfg(not(stage0))] // remove cfg after new snapshot
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
weak: atomic::AtomicUsize::new(1),
data: data,
};
- Arc { _ptr: unsafe { NonZero::new(Box::into_raw(x)) } }
+ Arc { _ptr: unsafe { Shared::new(Box::into_raw(x)) } }
}
/// Unwraps the contained value if the `Arc<T>` has only one strong reference.
#[stable(feature = "arc_unique", since = "1.4.0")]
pub fn try_unwrap(this: Self) -> Result<T, Self> {
// See `drop` for why all these atomics are like this
- if this.inner().strong.compare_and_swap(1, 0, Release) != 1 { return Err(this) }
+ if this.inner().strong.compare_and_swap(1, 0, Release) != 1 {
+ return Err(this)
+ }
atomic::fence(Acquire);
let cur = this.inner().weak.load(Relaxed);
// check if the weak counter is currently "locked"; if so, spin.
- if cur == usize::MAX { continue }
+ if cur == usize::MAX {
+ continue
+ }
// NOTE: this code currently ignores the possibility of overflow
// into usize::MAX; in general both Rc and Arc need to be adjusted
// We abort because such a program is incredibly degenerate, and we
// don't care to support it.
if old_size > MAX_REFCOUNT {
- unsafe { abort(); }
+ unsafe {
+ abort();
+ }
}
Arc { _ptr: self._ptr }
///
/// } // implicit drop
/// ```
+ #[unsafe_destructor_blind_to_params]
#[inline]
fn drop(&mut self) {
// This structure has #[unsafe_no_drop_flag], so this drop glue may run
// Because `fetch_sub` is already atomic, we do not need to synchronize
// with other threads unless we are going to delete the object. This
// same logic applies to the below `fetch_sub` to the `weak` count.
- if self.inner().strong.fetch_sub(1, Release) != 1 { return }
+ if self.inner().strong.fetch_sub(1, Release) != 1 {
+ return
+ }
// This fence is needed to prevent reordering of use of the data and
// deletion of the data. Because it is marked `Release`, the decreasing
atomic::fence(Acquire);
unsafe {
- self.drop_slow()
+ self.drop_slow();
}
}
}
// "stale" read of 0 is fine), and any other value is
// confirmed via the CAS below.
let n = inner.strong.load(Relaxed);
- if n == 0 { return None }
+ if n == 0 {
+ return None
+ }
// Relaxed is valid for the same reason it is on Arc's Clone impl
let old = inner.strong.compare_and_swap(n, n + 1, Relaxed);
- if old == n { return Some(Arc { _ptr: self._ptr }) }
+ if old == n {
+ return Some(Arc { _ptr: self._ptr })
+ }
}
}
// See comments in Arc::clone() for why we do this (for mem::forget).
if old_size > MAX_REFCOUNT {
- unsafe { abort(); }
+ unsafe {
+ abort();
+ }
}
return Weak { _ptr: self._ptr }
// ref, which can only happen after the lock is released.
if self.inner().weak.fetch_sub(1, Release) == 1 {
atomic::fence(Acquire);
- unsafe { deallocate(ptr as *mut u8,
- size_of_val(&*ptr),
- align_of_val(&*ptr)) }
+ unsafe { deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr)) }
}
}
}
///
/// five == Arc::new(5);
/// ```
- fn eq(&self, other: &Arc<T>) -> bool { *(*self) == *(*other) }
+ fn eq(&self, other: &Arc<T>) -> bool {
+ *(*self) == *(*other)
+ }
/// Inequality for two `Arc<T>`s.
///
///
/// five != Arc::new(5);
/// ```
- fn ne(&self, other: &Arc<T>) -> bool { *(*self) != *(*other) }
+ fn ne(&self, other: &Arc<T>) -> bool {
+ *(*self) != *(*other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + PartialOrd> PartialOrd for Arc<T> {
///
/// five < Arc::new(5);
/// ```
- fn lt(&self, other: &Arc<T>) -> bool { *(*self) < *(*other) }
+ fn lt(&self, other: &Arc<T>) -> bool {
+ *(*self) < *(*other)
+ }
/// 'Less-than or equal to' comparison for two `Arc<T>`s.
///
///
/// five <= Arc::new(5);
/// ```
- fn le(&self, other: &Arc<T>) -> bool { *(*self) <= *(*other) }
+ fn le(&self, other: &Arc<T>) -> bool {
+ *(*self) <= *(*other)
+ }
/// Greater-than comparison for two `Arc<T>`s.
///
///
/// five > Arc::new(5);
/// ```
- fn gt(&self, other: &Arc<T>) -> bool { *(*self) > *(*other) }
+ fn gt(&self, other: &Arc<T>) -> bool {
+ *(*self) > *(*other)
+ }
/// 'Greater-than or equal to' comparison for two `Arc<T>`s.
///
///
/// five >= Arc::new(5);
/// ```
- fn ge(&self, other: &Arc<T>) -> bool { *(*self) >= *(*other) }
+ fn ge(&self, other: &Arc<T>) -> bool {
+ *(*self) >= *(*other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Ord> Ord for Arc<T> {
- fn cmp(&self, other: &Arc<T>) -> Ordering { (**self).cmp(&**other) }
+ fn cmp(&self, other: &Arc<T>) -> Ordering {
+ (**self).cmp(&**other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Eq> Eq for Arc<T> {}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Default> Default for Arc<T> {
#[stable(feature = "rust1", since = "1.0.0")]
- fn default() -> Arc<T> { Arc::new(Default::default()) }
+ fn default() -> Arc<T> {
+ Arc::new(Default::default())
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
#[test]
fn weak_self_cyclic() {
struct Cycle {
- x: Mutex<Option<Weak<Cycle>>>
+ x: Mutex<Option<Weak<Cycle>>>,
}
let a = Arc::new(Cycle { x: Mutex::new(None) });
// Make sure deriving works with Arc<T>
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)]
- struct Foo { inner: Arc<i32> }
+ struct Foo {
+ inner: Arc<i32>,
+ }
#[test]
fn test_unsized() {
}
impl<T: ?Sized> borrow::Borrow<T> for Arc<T> {
- fn borrow(&self) -> &T { &**self }
+ fn borrow(&self) -> &T {
+ &**self
+ }
+}
+
+#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
+impl<T: ?Sized> AsRef<T> for Arc<T> {
+ fn as_ref(&self) -> &T {
+ &**self
+ }
}
use core::ops::{CoerceUnsized, Deref, DerefMut};
use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace};
use core::ptr::{self, Unique};
-use core::raw::{TraitObject};
+use core::raw::TraitObject;
/// A value that represents the heap. This is the default place that the `box`
/// keyword allocates into when no place is supplied.
/// use std::boxed::HEAP;
///
/// fn main() {
-/// let foo = box(HEAP) 5;
+/// let foo: Box<i32> = in HEAP { 5 };
/// let foo = box 5;
/// }
/// ```
-#[lang = "exchange_heap"]
#[unstable(feature = "box_heap",
reason = "may be renamed; uncertain about custom allocator design",
issue = "27779")]
reason = "may be renamed; uncertain about custom allocator design",
issue = "27779")]
#[derive(Copy, Clone)]
-pub struct ExchangeHeapSingleton { _force_singleton: () }
+pub struct ExchangeHeapSingleton {
+ _force_singleton: (),
+}
/// A pointer type for heap allocation.
///
#[unstable(feature = "placement_in",
reason = "placement box design is still being worked out.",
issue = "27779")]
-pub struct IntermediateBox<T: ?Sized>{
+pub struct IntermediateBox<T: ?Sized> {
ptr: *mut u8,
size: usize,
align: usize,
impl<T> Place<T> for IntermediateBox<T> {
fn pointer(&mut self) -> *mut T {
- unsafe { ::core::mem::transmute(self.ptr) }
+ self.ptr as *mut T
}
}
let p = if size == 0 {
heap::EMPTY as *mut u8
} else {
- let p = unsafe {
- heap::allocate(size, align)
- };
+ let p = unsafe { heap::allocate(size, align) };
if p.is_null() {
panic!("Box make_place allocation failure.");
}
p
};
- IntermediateBox { ptr: p, size: size, align: align, marker: marker::PhantomData }
+ IntermediateBox {
+ ptr: p,
+ size: size,
+ align: align,
+ marker: marker::PhantomData,
+ }
}
impl<T> BoxPlace<T> for IntermediateBox<T> {
- fn make_place() -> IntermediateBox<T> { make_place() }
+ fn make_place() -> IntermediateBox<T> {
+ make_place()
+ }
}
impl<T> InPlace<T> for IntermediateBox<T> {
type Owner = Box<T>;
- unsafe fn finalize(self) -> Box<T> { finalize(self) }
+ unsafe fn finalize(self) -> Box<T> {
+ finalize(self)
+ }
}
impl<T> Boxed for Box<T> {
type Data = T;
type Place = IntermediateBox<T>;
- unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> { finalize(b) }
+ unsafe fn finalize(b: IntermediateBox<T>) -> Box<T> {
+ finalize(b)
+ }
}
impl<T> Placer<T> for ExchangeHeapSingleton {
impl<T: ?Sized> Drop for IntermediateBox<T> {
fn drop(&mut self) {
if self.size > 0 {
- unsafe {
- heap::deallocate(self.ptr, self.size, self.align)
- }
+ unsafe { heap::deallocate(self.ptr, self.size, self.align) }
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Default> Default for Box<T> {
#[stable(feature = "rust1", since = "1.0.0")]
- fn default() -> Box<T> { box Default::default() }
+ fn default() -> Box<T> {
+ box Default::default()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Default for Box<[T]> {
#[stable(feature = "rust1", since = "1.0.0")]
- fn default() -> Box<[T]> { Box::<[T; 0]>::new([]) }
+ fn default() -> Box<[T]> {
+ Box::<[T; 0]>::new([])
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
/// let x = Box::new(5);
/// let y = x.clone();
/// ```
+ #[rustfmt_skip]
#[inline]
- fn clone(&self) -> Box<T> { box {(**self).clone()} }
+ fn clone(&self) -> Box<T> {
+ box { (**self).clone() }
+ }
/// Copies `source`'s contents into `self` without creating a new allocation.
///
/// # Examples
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + PartialEq> PartialEq for Box<T> {
#[inline]
- fn eq(&self, other: &Box<T>) -> bool { PartialEq::eq(&**self, &**other) }
+ fn eq(&self, other: &Box<T>) -> bool {
+ PartialEq::eq(&**self, &**other)
+ }
#[inline]
- fn ne(&self, other: &Box<T>) -> bool { PartialEq::ne(&**self, &**other) }
+ fn ne(&self, other: &Box<T>) -> bool {
+ PartialEq::ne(&**self, &**other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + PartialOrd> PartialOrd for Box<T> {
PartialOrd::partial_cmp(&**self, &**other)
}
#[inline]
- fn lt(&self, other: &Box<T>) -> bool { PartialOrd::lt(&**self, &**other) }
+ fn lt(&self, other: &Box<T>) -> bool {
+ PartialOrd::lt(&**self, &**other)
+ }
#[inline]
- fn le(&self, other: &Box<T>) -> bool { PartialOrd::le(&**self, &**other) }
+ fn le(&self, other: &Box<T>) -> bool {
+ PartialOrd::le(&**self, &**other)
+ }
#[inline]
- fn ge(&self, other: &Box<T>) -> bool { PartialOrd::ge(&**self, &**other) }
+ fn ge(&self, other: &Box<T>) -> bool {
+ PartialOrd::ge(&**self, &**other)
+ }
#[inline]
- fn gt(&self, other: &Box<T>) -> bool { PartialOrd::gt(&**self, &**other) }
+ fn gt(&self, other: &Box<T>) -> bool {
+ PartialOrd::gt(&**self, &**other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized + Ord> Ord for Box<T> {
unsafe {
// Get the raw representation of the trait object
let raw = Box::into_raw(self);
- let to: TraitObject =
- mem::transmute::<*mut Any, TraitObject>(raw);
+ let to: TraitObject = mem::transmute::<*mut Any, TraitObject>(raw);
// Extract the data pointer
Ok(Box::from_raw(to.data as *mut T))
impl<T: ?Sized> Deref for Box<T> {
type Target = T;
- fn deref(&self) -> &T { &**self }
+ fn deref(&self) -> &T {
+ &**self
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> DerefMut for Box<T> {
- fn deref_mut(&mut self) -> &mut T { &mut **self }
+ fn deref_mut(&mut self) -> &mut T {
+ &mut **self
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator + ?Sized> Iterator for Box<I> {
type Item = I::Item;
- fn next(&mut self) -> Option<I::Item> { (**self).next() }
- fn size_hint(&self) -> (usize, Option<usize>) { (**self).size_hint() }
+ fn next(&mut self) -> Option<I::Item> {
+ (**self).next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (**self).size_hint()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
- fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
+ fn next_back(&mut self) -> Option<I::Item> {
+ (**self).next_back()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
fn clone(&self) -> Self {
let mut new = BoxBuilder {
data: RawVec::with_capacity(self.len()),
- len: 0
+ len: 0,
};
let mut target = new.data.ptr();
}
impl<T: ?Sized> borrow::Borrow<T> for Box<T> {
- fn borrow(&self) -> &T { &**self }
+ fn borrow(&self) -> &T {
+ &**self
+ }
}
impl<T: ?Sized> borrow::BorrowMut<T> for Box<T> {
- fn borrow_mut(&mut self) -> &mut T { &mut **self }
+ fn borrow_mut(&mut self) -> &mut T {
+ &mut **self
+ }
+}
+
+#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
+impl<T: ?Sized> AsRef<T> for Box<T> {
+ fn as_ref(&self) -> &T {
+ &**self
+ }
+}
+
+#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
+impl<T: ?Sized> AsMut<T> for Box<T> {
+ fn as_mut(&mut self) -> &mut T {
+ &mut **self
+ }
}
let b = Box::new(Test) as Box<Any>;
match a.downcast::<i32>() {
- Ok(a) => { assert!(a == Box::new(8)); }
- Err(..) => panic!()
+ Ok(a) => {
+ assert!(a == Box::new(8));
+ }
+ Err(..) => panic!(),
}
match b.downcast::<Test>() {
- Ok(a) => { assert!(a == Box::new(Test)); }
- Err(..) => panic!()
+ Ok(a) => {
+ assert!(a == Box::new(Test));
+ }
+ Err(..) => panic!(),
}
let a = Box::new(8) as Box<Any>;
#[test]
fn deref() {
- fn homura<T: Deref<Target=i32>>(_: T) { }
+ fn homura<T: Deref<Target = i32>>(_: T) {
+ }
homura(Box::new(765));
}
#[allocator]
fn __rust_allocate(size: usize, align: usize) -> *mut u8;
fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize);
- fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> *mut u8;
- fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> usize;
+ fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8;
+ fn __rust_reallocate_inplace(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize;
fn __rust_usable_size(size: usize, align: usize) -> usize;
}
#[inline(always)]
fn check_size_and_alignment(size: usize, align: usize) {
debug_assert!(size != 0);
- debug_assert!(size <= isize::MAX as usize, "Tried to allocate too much: {} bytes", size);
- debug_assert!(usize::is_power_of_two(align), "Invalid alignment of allocation: {}", align);
+ debug_assert!(size <= isize::MAX as usize,
+ "Tried to allocate too much: {} bytes",
+ size);
+ debug_assert!(usize::is_power_of_two(align),
+ "Invalid alignment of allocation: {}",
+ align);
}
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
#[inline]
-pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> usize {
+pub unsafe fn reallocate_inplace(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
check_size_and_alignment(size, align);
__rust_reallocate_inplace(ptr, old_size, size, align)
}
EMPTY as *mut u8
} else {
let ptr = allocate(size, align);
- if ptr.is_null() { ::oom() }
+ if ptr.is_null() {
+ ::oom()
+ }
ptr
}
}
unsafe {
let size = 4000;
let ptr = heap::allocate(size, 8);
- if ptr.is_null() { ::oom() }
+ if ptr.is_null() {
+ ::oom()
+ }
let ret = heap::reallocate_inplace(ptr, size, size, 8);
heap::deallocate(ptr, size, 8);
assert_eq!(ret, heap::usable_size(size, 8));
#![feature(placement_in_syntax)]
#![feature(placement_new_protocol)]
#![feature(raw)]
+#![feature(shared)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
+// SNAP 1af31d4
+#![allow(unused_features)]
+// SNAP 1af31d4
+#![allow(unused_attributes)]
+#![feature(dropck_parametricity)]
#![feature(unsize)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
#![cfg_attr(stage0, feature(alloc_system))]
#![cfg_attr(not(stage0), feature(needs_allocator))]
-#![cfg_attr(test, feature(test, rustc_private))]
+#![cfg_attr(test, feature(test, rustc_private, box_heap))]
#[cfg(stage0)]
extern crate alloc_system;
// Allow testing this library
-#[cfg(test)] #[macro_use] extern crate std;
-#[cfg(test)] #[macro_use] extern crate log;
+#[cfg(test)]
+#[macro_use]
+extern crate std;
+#[cfg(test)]
+#[macro_use]
+extern crate log;
// Heaps provided for low-level allocation strategies
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
-mod boxed { pub use std::boxed::{Box, HEAP}; }
+mod boxed {
+ pub use std::boxed::{Box, HEAP};
+}
#[cfg(test)]
mod boxed_test;
pub mod arc;
pub fn new() -> Self {
unsafe {
// !0 is usize::MAX. This branch should be stripped at compile time.
- let cap = if mem::size_of::<T>() == 0 { !0 } else { 0 };
+ let cap = if mem::size_of::<T>() == 0 {
+ !0
+ } else {
+ 0
+ };
// heap::EMPTY doubles as "unallocated" and "zero-sized allocation"
- RawVec { ptr: Unique::new(heap::EMPTY as *mut T), cap: cap }
+ RawVec {
+ ptr: Unique::new(heap::EMPTY as *mut T),
+ cap: cap,
+ }
}
}
} else {
let align = mem::align_of::<T>();
let ptr = heap::allocate(alloc_size, align);
- if ptr.is_null() { oom() }
+ if ptr.is_null() {
+ oom()
+ }
ptr
};
- RawVec { ptr: Unique::new(ptr as *mut _), cap: cap }
+ RawVec {
+ ptr: Unique::new(ptr as *mut _),
+ cap: cap,
+ }
}
}
/// Reconstitutes a RawVec from a pointer and capacity.
///
- /// # Undefined Behaviour
+ /// # Undefined Behavior
///
/// The ptr must be allocated, and with the given capacity. The
/// capacity cannot exceed `isize::MAX` (only a concern on 32-bit systems).
/// If the ptr and capacity come from a RawVec, then this is guaranteed.
pub unsafe fn from_raw_parts(ptr: *mut T, cap: usize) -> Self {
- RawVec { ptr: Unique::new(ptr), cap: cap }
+ RawVec {
+ ptr: Unique::new(ptr),
+ cap: cap,
+ }
}
/// Converts a `Box<[T]>` into a `RawVec<T>`.
///
/// This will always be `usize::MAX` if `T` is zero-sized.
pub fn cap(&self) -> usize {
- if mem::size_of::<T>() == 0 { !0 } else { self.cap }
+ if mem::size_of::<T>() == 0 {
+ !0
+ } else {
+ self.cap
+ }
}
/// Doubles the size of the type's backing allocation. This is common enough
let (new_cap, ptr) = if self.cap == 0 {
// skip to 4 because tiny Vec's are dumb; but not if that would cause overflow
- let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 };
+ let new_cap = if elem_size > (!0) / 8 {
+ 1
+ } else {
+ 4
+ };
let ptr = heap::allocate(new_cap * elem_size, align);
(new_cap, ptr)
} else {
};
// If allocate or reallocate fail, we'll get `null` back
- if ptr.is_null() { oom() }
+ if ptr.is_null() {
+ oom()
+ }
self.ptr = Unique::new(ptr as *mut _);
self.cap = new_cap;
///
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
/// the requested space. This is not really unsafe, but the unsafe
- /// code *you* write that relies on the behaviour of this function may break.
+ /// code *you* write that relies on the behavior of this function may break.
///
/// # Panics
///
// Don't actually need any more capacity.
// Wrapping in case they gave a bad `used_cap`.
- if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; }
+ if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
+ return;
+ }
// Nothing we can really do about these checks :(
let new_cap = used_cap.checked_add(needed_extra_cap).expect("capacity overflow");
};
// If allocate or reallocate fail, we'll get `null` back
- if ptr.is_null() { oom() }
+ if ptr.is_null() {
+ oom()
+ }
self.ptr = Unique::new(ptr as *mut _);
self.cap = new_cap;
/// Ensures that the buffer contains at least enough space to hold
/// `used_cap + needed_extra_cap` elements. If it doesn't already have
/// enough capacity, will reallocate enough space plus comfortable slack
- /// space to get amortized `O(1)` behaviour. Will limit this behaviour
+ /// space to get amortized `O(1)` behavior. Will limit this behavior
/// if it would needlessly cause itself to panic.
///
/// If `used_cap` exceeds `self.cap()`, this may fail to actually allocate
/// the requested space. This is not really unsafe, but the unsafe
- /// code *you* write that relies on the behaviour of this function may break.
+ /// code *you* write that relies on the behavior of this function may break.
///
/// This is ideal for implementing a bulk-push operation like `extend`.
///
// Don't actually need any more capacity.
// Wrapping in case they give a bas `used_cap`
- if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { return; }
+ if self.cap().wrapping_sub(used_cap) >= needed_extra_cap {
+ return;
+ }
// Nothing we can really do about these checks :(
let new_cap = used_cap.checked_add(needed_extra_cap)
};
// If allocate or reallocate fail, we'll get `null` back
- if ptr.is_null() { oom() }
+ if ptr.is_null() {
+ oom()
+ }
self.ptr = Unique::new(ptr as *mut _);
self.cap = new_cap;
self.cap * elem_size,
amount * elem_size,
align);
- if ptr.is_null() { oom() }
+ if ptr.is_null() {
+ oom()
+ }
self.ptr = Unique::new(ptr as *mut _);
}
self.cap = amount;
/// Converts the entire buffer into `Box<[T]>`.
///
- /// While it is not *strictly* Undefined Behaviour to call
+ /// While it is not *strictly* Undefined Behavior to call
/// this procedure while some of the RawVec is unintialized,
/// it cetainly makes it trivial to trigger it.
///
}
impl<T> Drop for RawVec<T> {
+ #[unsafe_destructor_blind_to_params]
/// Frees the memory owned by the RawVec *without* trying to Drop its contents.
fn drop(&mut self) {
let elem_size = mem::size_of::<T>();
#[inline]
fn alloc_guard(alloc_size: usize) {
if core::usize::BITS < 64 {
- assert!(alloc_size <= ::core::isize::MAX as usize, "capacity overflow");
+ assert!(alloc_size <= ::core::isize::MAX as usize,
+ "capacity overflow");
}
}
use core::intrinsics::{assume, drop_in_place, abort};
use core::marker::{self, Unsize};
use core::mem::{self, align_of_val, size_of_val, forget};
-use core::nonzero::NonZero;
use core::ops::{CoerceUnsized, Deref};
-use core::ptr;
+use core::ptr::{self, Shared};
use heap::deallocate;
pub struct Rc<T: ?Sized> {
// FIXME #12808: strange names to try to avoid interfering with field
// accesses of the contained type via Deref
- _ptr: NonZero<*mut RcBox<T>>,
+ _ptr: Shared<RcBox<T>>,
}
impl<T: ?Sized> !marker::Send for Rc<T> {}
impl<T: ?Sized> !marker::Sync for Rc<T> {}
+#[cfg(not(stage0))] // remove cfg after new snapshot
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
impl<T> Rc<T> {
// pointers, which ensures that the weak destructor never frees
// the allocation while the strong destructor is running, even
// if the weak pointer is stored inside the strong one.
- _ptr: NonZero::new(Box::into_raw(box RcBox {
+ _ptr: Shared::new(Box::into_raw(box RcBox {
strong: Cell::new(1),
weak: Cell::new(1),
- value: value
+ value: value,
})),
}
}
#[inline]
#[unstable(feature = "rc_counts", reason = "not clearly useful",
issue = "28356")]
- pub fn weak_count(this: &Self) -> usize { this.weak() - 1 }
+ pub fn weak_count(this: &Self) -> usize {
+ this.weak() - 1
+ }
/// Get the number of strong references to this value.
#[inline]
#[unstable(feature = "rc_counts", reason = "not clearly useful",
issue = "28356")]
- pub fn strong_count(this: &Self) -> usize { this.strong() }
+ pub fn strong_count(this: &Self) -> usize {
+ this.strong()
+ }
/// Returns true if there are no other `Rc` or `Weak<T>` values that share
/// the same inner value.
///
/// } // implicit drop
/// ```
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
unsafe {
let ptr = *self._ptr;
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
- ptr as *const () as usize != mem::POST_DROP_USIZE {
+ ptr as *const () as usize != mem::POST_DROP_USIZE {
self.dec_strong();
if self.strong() == 0 {
// destroy the contained object
self.dec_weak();
if self.weak() == 0 {
- deallocate(ptr as *mut u8,
- size_of_val(&*ptr),
- align_of_val(&*ptr))
+ deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
}
}
}
/// five == Rc::new(5);
/// ```
#[inline(always)]
- fn eq(&self, other: &Rc<T>) -> bool { **self == **other }
+ fn eq(&self, other: &Rc<T>) -> bool {
+ **self == **other
+ }
/// Inequality for two `Rc<T>`s.
///
/// five != Rc::new(5);
/// ```
#[inline(always)]
- fn ne(&self, other: &Rc<T>) -> bool { **self != **other }
+ fn ne(&self, other: &Rc<T>) -> bool {
+ **self != **other
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
/// five < Rc::new(5);
/// ```
#[inline(always)]
- fn lt(&self, other: &Rc<T>) -> bool { **self < **other }
+ fn lt(&self, other: &Rc<T>) -> bool {
+ **self < **other
+ }
/// 'Less-than or equal to' comparison for two `Rc<T>`s.
///
/// five <= Rc::new(5);
/// ```
#[inline(always)]
- fn le(&self, other: &Rc<T>) -> bool { **self <= **other }
+ fn le(&self, other: &Rc<T>) -> bool {
+ **self <= **other
+ }
/// Greater-than comparison for two `Rc<T>`s.
///
/// five > Rc::new(5);
/// ```
#[inline(always)]
- fn gt(&self, other: &Rc<T>) -> bool { **self > **other }
+ fn gt(&self, other: &Rc<T>) -> bool {
+ **self > **other
+ }
/// 'Greater-than or equal to' comparison for two `Rc<T>`s.
///
/// five >= Rc::new(5);
/// ```
#[inline(always)]
- fn ge(&self, other: &Rc<T>) -> bool { **self >= **other }
+ fn ge(&self, other: &Rc<T>) -> bool {
+ **self >= **other
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
/// five.partial_cmp(&Rc::new(5));
/// ```
#[inline]
- fn cmp(&self, other: &Rc<T>) -> Ordering { (**self).cmp(&**other) }
+ fn cmp(&self, other: &Rc<T>) -> Ordering {
+ (**self).cmp(&**other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Weak<T: ?Sized> {
// FIXME #12808: strange names to try to avoid interfering with
// field accesses of the contained type via Deref
- _ptr: NonZero<*mut RcBox<T>>,
+ _ptr: Shared<RcBox<T>>,
}
impl<T: ?Sized> !marker::Send for Weak<T> {}
impl<T: ?Sized> !marker::Sync for Weak<T> {}
+#[cfg(not(stage0))] // remove cfg after new snapshot
impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Weak<U>> for Weak<T> {}
impl<T: ?Sized> Weak<T> {
unsafe {
let ptr = *self._ptr;
if !(*(&ptr as *const _ as *const *const ())).is_null() &&
- ptr as *const () as usize != mem::POST_DROP_USIZE {
+ ptr as *const () as usize != mem::POST_DROP_USIZE {
self.dec_weak();
// the weak count starts at 1, and will only go to zero if all
// the strong pointers have disappeared.
if self.weak() == 0 {
- deallocate(ptr as *mut u8, size_of_val(&*ptr),
- align_of_val(&*ptr))
+ deallocate(ptr as *mut u8, size_of_val(&*ptr), align_of_val(&*ptr))
}
}
}
fn inner(&self) -> &RcBox<T>;
#[inline]
- fn strong(&self) -> usize { self.inner().strong.get() }
+ fn strong(&self) -> usize {
+ self.inner().strong.get()
+ }
#[inline]
fn inc_strong(&self) {
}
#[inline]
- fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); }
+ fn dec_strong(&self) {
+ self.inner().strong.set(self.strong() - 1);
+ }
#[inline]
- fn weak(&self) -> usize { self.inner().weak.get() }
+ fn weak(&self) -> usize {
+ self.inner().weak.get()
+ }
#[inline]
fn inc_weak(&self) {
}
#[inline]
- fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); }
+ fn dec_weak(&self) {
+ self.inner().weak.set(self.weak() - 1);
+ }
}
impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
#[test]
fn weak_self_cyclic() {
struct Cycle {
- x: RefCell<Option<Weak<Cycle>>>
+ x: RefCell<Option<Weak<Cycle>>>,
}
let a = Rc::new(Cycle { x: RefCell::new(None) });
}
impl<T: ?Sized> borrow::Borrow<T> for Rc<T> {
- fn borrow(&self) -> &T { &**self }
+ fn borrow(&self) -> &T {
+ &**self
+ }
+}
+
+#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")]
+impl<T: ?Sized> AsRef<T> for Rc<T> {
+ fn as_ref(&self) -> &T {
+ &**self
+ }
}
use libc::{c_int, c_void, size_t};
+// Linkage directives to pull in jemalloc and its dependencies.
+//
+// On some platforms we need to be sure to link in `pthread` which jemalloc
+// depends on, and specifically on android we need to also link to libgcc.
+// Currently jemalloc is compiled with gcc which will generate calls to
+// intrinsics that are libgcc specific (e.g. those intrinsics aren't present in
+// libcompiler-rt), so link that in to get that support.
#[link(name = "jemalloc", kind = "static")]
+#[cfg_attr(target_os = "android", link(name = "gcc"))]
+#[cfg_attr(all(not(windows),
+ not(target_os = "android"),
+ not(target_env = "musl")),
+ link(name = "pthread"))]
extern {
fn je_mallocx(size: size_t, flags: c_int) -> *mut c_void;
fn je_rallocx(ptr: *mut c_void, size: size_t, flags: c_int) -> *mut c_void;
- fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t,
- flags: c_int) -> size_t;
+ fn je_xallocx(ptr: *mut c_void, size: size_t, extra: size_t, flags: c_int) -> size_t;
fn je_sdallocx(ptr: *mut c_void, size: size_t, flags: c_int);
fn je_nallocx(size: size_t, flags: c_int) -> size_t;
}
-// -lpthread needs to occur after -ljemalloc, the earlier argument isn't enough
-#[cfg(all(not(windows),
- not(target_os = "android"),
- not(target_env = "musl")))]
-#[link(name = "pthread")]
-extern {}
-
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
// constant at the call site and the branch will be optimized out.
const MIN_ALIGN: usize = 16;
// MALLOCX_ALIGN(a) macro
-fn mallocx_align(a: usize) -> c_int { a.trailing_zeros() as c_int }
+fn mallocx_align(a: usize) -> c_int {
+ a.trailing_zeros() as c_int
+}
fn align_to_flags(align: usize) -> c_int {
- if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
+ if align <= MIN_ALIGN {
+ 0
+ } else {
+ mallocx_align(align)
+ }
}
#[no_mangle]
-pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
+pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
let flags = align_to_flags(align);
unsafe { je_mallocx(size as size_t, flags) as *mut u8 }
}
#[no_mangle]
-pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+pub extern "C" fn __rust_reallocate(ptr: *mut u8,
+ _old_size: usize,
+ size: usize,
+ align: usize)
+ -> *mut u8 {
let flags = align_to_flags(align);
unsafe { je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8 }
}
#[no_mangle]
-pub extern fn __rust_reallocate_inplace(ptr: *mut u8, _old_size: usize,
- size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
+ _old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
let flags = align_to_flags(align);
unsafe { je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) as usize }
}
#[no_mangle]
-pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
let flags = align_to_flags(align);
unsafe { je_sdallocx(ptr as *mut c_void, old_size as size_t, flags) }
}
#[no_mangle]
-pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
let flags = align_to_flags(align);
unsafe { je_nallocx(size as size_t, flags) as usize }
}
const MIN_ALIGN: usize = 16;
#[no_mangle]
-pub extern fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
+pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
unsafe { imp::allocate(size, align) }
}
#[no_mangle]
-pub extern fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
+pub extern "C" fn __rust_deallocate(ptr: *mut u8, old_size: usize, align: usize) {
unsafe { imp::deallocate(ptr, old_size, align) }
}
#[no_mangle]
-pub extern fn __rust_reallocate(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+pub extern "C" fn __rust_reallocate(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> *mut u8 {
unsafe { imp::reallocate(ptr, old_size, size, align) }
}
#[no_mangle]
-pub extern fn __rust_reallocate_inplace(ptr: *mut u8, old_size: usize,
- size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_reallocate_inplace(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
unsafe { imp::reallocate_inplace(ptr, old_size, size, align) }
}
#[no_mangle]
-pub extern fn __rust_usable_size(size: usize, align: usize) -> usize {
+pub extern "C" fn __rust_usable_size(size: usize, align: usize) -> usize {
imp::usable_size(size, align)
}
#[cfg(not(target_os = "android"))]
fn posix_memalign(memptr: *mut *mut libc::c_void,
align: libc::size_t,
- size: libc::size_t) -> libc::c_int;
+ size: libc::size_t)
+ -> libc::c_int;
}
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
#[cfg(not(target_os = "android"))]
unsafe fn more_aligned_malloc(size: usize, align: usize) -> *mut u8 {
let mut out = ptr::null_mut();
- let ret = posix_memalign(&mut out,
- align as libc::size_t,
- size as libc::size_t);
+ let ret = posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
if ret != 0 {
ptr::null_mut()
} else {
}
}
- pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
} else {
}
}
- pub unsafe fn reallocate_inplace(_ptr: *mut u8, old_size: usize, _size: usize,
- _align: usize) -> usize {
+ pub unsafe fn reallocate_inplace(_ptr: *mut u8,
+ old_size: usize,
+ _size: usize,
+ _align: usize)
+ -> usize {
old_size
}
extern "system" {
fn GetProcessHeap() -> HANDLE;
fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
- fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID,
- dwBytes: SIZE_T) -> LPVOID;
+ fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
}
if align <= MIN_ALIGN {
HeapAlloc(GetProcessHeap(), 0, size as SIZE_T) as *mut u8
} else {
- let ptr = HeapAlloc(GetProcessHeap(), 0,
- (size + align) as SIZE_T) as *mut u8;
- if ptr.is_null() { return ptr }
+ let ptr = HeapAlloc(GetProcessHeap(), 0, (size + align) as SIZE_T) as *mut u8;
+ if ptr.is_null() {
+ return ptr
+ }
align_ptr(ptr, align)
}
}
- pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize,
- align: usize) -> *mut u8 {
+ pub unsafe fn reallocate(ptr: *mut u8, _old_size: usize, size: usize, align: usize) -> *mut u8 {
if align <= MIN_ALIGN {
HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, size as SIZE_T) as *mut u8
} else {
let header = get_header(ptr);
- let new = HeapReAlloc(GetProcessHeap(), 0, header.0 as LPVOID,
+ let new = HeapReAlloc(GetProcessHeap(),
+ 0,
+ header.0 as LPVOID,
(size + align) as SIZE_T) as *mut u8;
- if new.is_null() { return new }
+ if new.is_null() {
+ return new
+ }
align_ptr(new, align)
}
}
- pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
- align: usize) -> usize {
+ pub unsafe fn reallocate_inplace(ptr: *mut u8,
+ old_size: usize,
+ size: usize,
+ align: usize)
+ -> usize {
if align <= MIN_ALIGN {
- let new = HeapReAlloc(GetProcessHeap(), HEAP_REALLOC_IN_PLACE_ONLY,
- ptr as LPVOID, size as SIZE_T) as *mut u8;
- if new.is_null() { old_size } else { size }
+ let new = HeapReAlloc(GetProcessHeap(),
+ HEAP_REALLOC_IN_PLACE_ONLY,
+ ptr as LPVOID,
+ size as SIZE_T) as *mut u8;
+ if new.is_null() {
+ old_size
+ } else {
+ size
+ }
} else {
old_size
}
#![feature(ptr_as_ref)]
#![feature(raw)]
#![feature(staged_api)]
+#![feature(dropck_parametricity)]
#![cfg_attr(test, feature(test))]
+// SNAP 1af31d4
+#![allow(unused_features)]
+// SNAP 1af31d4
+#![allow(unused_attributes)]
+
extern crate alloc;
use std::cell::{Cell, RefCell};
head: RefCell<Chunk>,
copy_head: RefCell<Chunk>,
chunks: RefCell<Vec<Chunk>>,
- _marker: marker::PhantomData<*mut &'longer_than_self()>,
+ _marker: marker::PhantomData<*mut &'longer_than_self ()>,
}
impl<'a> Arena<'a> {
struct TyDesc {
drop_glue: fn(*const i8),
size: usize,
- align: usize
+ align: usize,
}
trait AllTypes { fn dummy(&self) { } }
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
self.chunks.borrow_mut().push(self.copy_head.borrow().clone());
- *self.copy_head.borrow_mut() =
- chunk((new_min_chunk_size + 1).next_power_of_two(), true);
+ *self.copy_head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), true);
self.alloc_copy_inner(n_bytes, align)
}
let copy_head = self.copy_head.borrow();
copy_head.fill.set(end);
- unsafe {
- copy_head.as_ptr().offset(start as isize)
- }
+ unsafe { copy_head.as_ptr().offset(start as isize) }
}
#[inline]
- fn alloc_copy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
+ fn alloc_copy<T, F>(&self, op: F) -> &mut T
+ where F: FnOnce() -> T
+ {
unsafe {
- let ptr = self.alloc_copy_inner(mem::size_of::<T>(),
- mem::align_of::<T>());
+ let ptr = self.alloc_copy_inner(mem::size_of::<T>(), mem::align_of::<T>());
let ptr = ptr as *mut T;
ptr::write(&mut (*ptr), op());
&mut *ptr
}
// Functions for the non-POD part of the arena
- fn alloc_noncopy_grow(&self, n_bytes: usize,
- align: usize) -> (*const u8, *const u8) {
+ fn alloc_noncopy_grow(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) {
// Allocate a new chunk.
let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size());
self.chunks.borrow_mut().push(self.head.borrow().clone());
- *self.head.borrow_mut() =
- chunk((new_min_chunk_size + 1).next_power_of_two(), false);
+ *self.head.borrow_mut() = chunk((new_min_chunk_size + 1).next_power_of_two(), false);
self.alloc_noncopy_inner(n_bytes, align)
}
#[inline]
- fn alloc_noncopy_inner(&self, n_bytes: usize,
- align: usize) -> (*const u8, *const u8) {
+ fn alloc_noncopy_inner(&self, n_bytes: usize, align: usize) -> (*const u8, *const u8) {
// Be careful to not maintain any `head` borrows active, because
// `alloc_noncopy_grow` borrows it mutably.
let (start, end, tydesc_start, head_capacity) = {
unsafe {
let buf = head.as_ptr();
- (buf.offset(tydesc_start as isize), buf.offset(start as isize))
+ (buf.offset(tydesc_start as isize),
+ buf.offset(start as isize))
}
}
#[inline]
- fn alloc_noncopy<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
+ fn alloc_noncopy<T, F>(&self, op: F) -> &mut T
+ where F: FnOnce() -> T
+ {
unsafe {
let tydesc = get_tydesc::<T>();
- let (ty_ptr, ptr) =
- self.alloc_noncopy_inner(mem::size_of::<T>(),
- mem::align_of::<T>());
+ let (ty_ptr, ptr) = self.alloc_noncopy_inner(mem::size_of::<T>(), mem::align_of::<T>());
let ty_ptr = ty_ptr as *mut usize;
let ptr = ptr as *mut T;
// Write in our tydesc along with a bit indicating that it
// has *not* been initialized yet.
*ty_ptr = bitpack_tydesc_ptr(tydesc, false);
// Actually initialize it
- ptr::write(&mut(*ptr), op());
+ ptr::write(&mut (*ptr), op());
// Now that we are done, update the tydesc to indicate that
// the object is there.
*ty_ptr = bitpack_tydesc_ptr(tydesc, true);
/// Allocates a new item in the arena, using `op` to initialize the value,
/// and returns a reference to it.
#[inline]
- pub fn alloc<T:'longer_than_self, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
+ pub fn alloc<T: 'longer_than_self, F>(&self, op: F) -> &mut T
+ where F: FnOnce() -> T
+ {
unsafe {
if intrinsics::needs_drop::<T>() {
self.alloc_noncopy(op)
for i in 0..10 {
// Arena allocate something with drop glue to make sure it
// doesn't leak.
- arena.alloc(|| { Rc::new(i) });
+ arena.alloc(|| Rc::new(i));
// Allocate something with funny size and alignment, to keep
// things interesting.
- arena.alloc(|| { [0u8, 1, 2] });
+ arena.alloc(|| [0u8, 1, 2]);
}
// Now, panic while allocating
arena.alloc::<Rc<i32>, _>(|| {
impl<T> TypedArenaChunk<T> {
#[inline]
- unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: usize)
- -> *mut TypedArenaChunk<T> {
+ unsafe fn new(next: *mut TypedArenaChunk<T>, capacity: usize) -> *mut TypedArenaChunk<T> {
let size = calculate_size::<T>(capacity);
- let chunk = allocate(size, mem::align_of::<TypedArenaChunk<T>>())
- as *mut TypedArenaChunk<T>;
- if chunk.is_null() { alloc::oom() }
+ let chunk =
+ allocate(size, mem::align_of::<TypedArenaChunk<T>>()) as *mut TypedArenaChunk<T>;
+ if chunk.is_null() {
+ alloc::oom()
+ }
(*chunk).next = next;
(*chunk).capacity = capacity;
chunk
let next = self.next;
let size = calculate_size::<T>(self.capacity);
let self_ptr: *mut TypedArenaChunk<T> = self;
- deallocate(self_ptr as *mut u8, size,
+ deallocate(self_ptr as *mut u8,
+ size,
mem::align_of::<TypedArenaChunk<T>>());
if !next.is_null() {
let capacity = (*next).capacity;
#[inline]
fn start(&self) -> *const u8 {
let this: *const TypedArenaChunk<T> = self;
- unsafe {
- round_up(this.offset(1) as usize, mem::align_of::<T>()) as *const u8
- }
+ unsafe { round_up(this.offset(1) as usize, mem::align_of::<T>()) as *const u8 }
}
// Returns a pointer to the end of the allocated space.
}
impl<T> Drop for TypedArena<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
unsafe {
// Determine how much was filled.
#[test]
fn test_arena_alloc_nested() {
- struct Inner { value: u8 }
- struct Outer<'a> { inner: &'a Inner }
- enum EI<'e> { I(Inner), O(Outer<'e>) }
+ struct Inner {
+ value: u8,
+ }
+ struct Outer<'a> {
+ inner: &'a Inner,
+ }
+ enum EI<'e> {
+ I(Inner),
+ O(Outer<'e>),
+ }
struct Wrap<'a>(TypedArena<EI<'a>>);
impl<'a> Wrap<'a> {
- fn alloc_inner<F:Fn() -> Inner>(&self, f: F) -> &Inner {
+ fn alloc_inner<F: Fn() -> Inner>(&self, f: F) -> &Inner {
let r: &EI = self.0.alloc(EI::I(f()));
if let &EI::I(ref i) = r {
i
panic!("mismatch");
}
}
- fn alloc_outer<F:Fn() -> Outer<'a>>(&self, f: F) -> &Outer {
+ fn alloc_outer<F: Fn() -> Outer<'a>>(&self, f: F) -> &Outer {
let r: &EI = self.0.alloc(EI::O(f()));
if let &EI::O(ref o) = r {
o
let arena = Wrap(TypedArena::new());
- let result = arena.alloc_outer(|| Outer {
- inner: arena.alloc_inner(|| Inner { value: 10 }) });
+ let result = arena.alloc_outer(|| {
+ Outer { inner: arena.alloc_inner(|| Inner { value: 10 }) }
+ });
assert_eq!(result.inner.value, 10);
}
pub fn test_copy() {
let arena = TypedArena::new();
for _ in 0..100000 {
- arena.alloc(Point {
- x: 1,
- y: 2,
- z: 3,
- });
+ arena.alloc(Point { x: 1, y: 2, z: 3 });
}
}
#[bench]
pub fn bench_copy(b: &mut Bencher) {
let arena = TypedArena::new();
- b.iter(|| {
- arena.alloc(Point {
- x: 1,
- y: 2,
- z: 3,
- })
- })
+ b.iter(|| arena.alloc(Point { x: 1, y: 2, z: 3 }))
}
#[bench]
pub fn bench_copy_nonarena(b: &mut Bencher) {
b.iter(|| {
- let _: Box<_> = box Point {
- x: 1,
- y: 2,
- z: 3,
- };
+ let _: Box<_> = box Point { x: 1, y: 2, z: 3 };
})
}
#[bench]
pub fn bench_copy_old_arena(b: &mut Bencher) {
let arena = Arena::new();
- b.iter(|| {
- arena.alloc(|| {
- Point {
- x: 1,
- y: 2,
- z: 3,
- }
- })
- })
+ b.iter(|| arena.alloc(|| Point { x: 1, y: 2, z: 3 }))
}
#[allow(dead_code)]
for _ in 0..100000 {
arena.alloc(Noncopy {
string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ array: vec!(1, 2, 3, 4, 5),
});
}
}
b.iter(|| {
arena.alloc(Noncopy {
string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ array: vec!(1, 2, 3, 4, 5),
})
})
}
b.iter(|| {
let _: Box<_> = box Noncopy {
string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ array: vec!(1, 2, 3, 4, 5),
};
})
}
pub fn bench_noncopy_old_arena(b: &mut Bencher) {
let arena = Arena::new();
b.iter(|| {
- arena.alloc(|| Noncopy {
- string: "hello world".to_string(),
- array: vec!( 1, 2, 3, 4, 5 ),
+ arena.alloc(|| {
+ Noncopy {
+ string: "hello world".to_string(),
+ array: vec!(1, 2, 3, 4, 5),
+ }
})
})
}
* configure.ac: Add --enable-host-shared.
* configure: Regenerate.
-\f
+
Copyright (C) 2013-2014 Free Software Foundation, Inc.
Copying and distribution of this file, with or without modification,
# met:
# (1) Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
+# notice, this list of conditions and the following disclaimer.
# (2) Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
-# distribution.
+# distribution.
# (3) The name of the author may not be used to
# endorse or promote products derived from this software without
# met:
# (1) Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
+# notice, this list of conditions and the following disclaimer.
# (2) Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
-# distribution.
+# distribution.
# (3) The name of the author may not be used to
# endorse or promote products derived from this software without
$(LDFLAGS) -o $@
SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
$(btest_SOURCES) $(stest_SOURCES)
-MULTISRCTOP =
-MULTIBUILDTOP =
-MULTIDIRS =
-MULTISUBDIR =
+MULTISRCTOP =
+MULTIBUILDTOP =
+MULTIDIRS =
+MULTISUBDIR =
MULTIDO = true
MULTICLEAN = true
am__can_run_installinfo = \
stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
@rm -f stamp-h1
cd $(top_builddir) && $(SHELL) ./config.status config.h
-$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
($(am__cd) $(top_srcdir) && $(AUTOHEADER))
rm -f stamp-h1
touch $@
echo "rm -f \"$${dir}/so_locations\""; \
rm -f "$${dir}/so_locations"; \
done
-libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES)
+libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES)
$(LINK) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS)
clean-checkPROGRAMS:
list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
echo " rm -f" $$list; \
rm -f $$list
-btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES)
+btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES)
@rm -f btest$(EXEEXT)
$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
-stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES)
+stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES)
@rm -f stest$(EXEEXT)
$(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS)
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
(unsigned int) bdata.index, j + 1);
bdata.failed = 1;
}
- }
+ }
check ("test3", 0, all, f3line, "f23", &bdata.failed);
check ("test3", 1, all, f2line, "f22", &bdata.failed);
# met:
# (1) Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
+# notice, this list of conditions and the following disclaimer.
# (2) Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
-# distribution.
-
+# distribution.
+
# (3) The name of the author may not be used to
# endorse or promote products derived from this software without
# specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
static int
find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
- struct dwarf_buf *unit_buf,
+ struct dwarf_buf *unit_buf,
const unsigned char *dwarf_str, size_t dwarf_str_size,
const unsigned char *dwarf_ranges,
size_t dwarf_ranges_size,
if (!advance (line_buf, hdrlen))
return 0;
-
+
hdr->min_insn_len = read_byte (&hdr_buf);
if (hdr->version < 4)
hdr->max_ops_per_insn = 1;
/* We don't care about default_is_stmt. */
read_byte (&hdr_buf);
-
+
hdr->line_base = read_sbyte (&hdr_buf);
hdr->line_range = read_byte (&hdr_buf);
/* This file declares various DWARF-related constants using a set of
macros which can be redefined by the including file.
-
+
The macros are in sections. Each section corresponds to a single
set of DWARF constants and has a corresponding key. The key is
used in all the macro names.
-
+
The sections are TAG (for DW_TAG_ constants), FORM (DW_FORM_), AT
(DW_AT_), OP (DW_OP_), ATE (DW_ATE_), and CFA (DW_CFA_).
-
+
Using TAG as an example, the following macros may be used for each
key:
-
+
DW_FIRST_TAG(name, value) - Introduce the first DW_TAG constant.
-
+
DW_TAG(name, value) - Define a subsequent constant.
-
+
DW_TAG_DUP(name, value) - Define a subsequent constant whose value
is a duplicate of some other constant. Not all keys use the _DUP
macro form. If more than one name shares a value, then the base
(DW_TAG) form will be the preferred name and DW_TAG_DUP will hold
any alternate names.
-
+
DW_END_TAG - Invoked at the end of the DW_TAG constants. */
DW_FIRST_TAG (DW_TAG_padding, 0x00)
DW_MACRO_GNU_lo_user = 0xe0,
DW_MACRO_GNU_hi_user = 0xff
};
-\f
+
/* @@@ For use with GNU frame unwind information. */
#define DW_EH_PE_absptr 0x00
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
met:
(1) Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
+ notice, this list of conditions and the following disclaimer.
(2) Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
- distribution.
-
+ distribution.
+
(3) The name of the author may not be used to
endorse or promote products derived from this software without
specific prior written permission.
/// item's ordering relative to any other item, as determined by the `Ord`
/// trait, changes while it is in the heap. This is normally only possible
/// through `Cell`, `RefCell`, global state, I/O, or unsafe code.
-#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BinaryHeap<T> {
data: Vec<T>,
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Clone> Clone for BinaryHeap<T> {
+ fn clone(&self) -> Self {
+ BinaryHeap { data: self.data.clone() }
+ }
+
+ fn clone_from(&mut self, source: &Self) {
+ self.data.clone_from(&source.data);
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Default for BinaryHeap<T> {
#[inline]
#[unstable(feature = "binary_heap_extras",
reason = "needs to be audited",
issue = "28147")]
+ #[deprecated(since = "1.5.0", reason = "use BinaryHeap::from instead")]
pub fn from_vec(vec: Vec<T>) -> BinaryHeap<T> {
- let mut heap = BinaryHeap { data: vec };
- let mut n = heap.len() / 2;
- while n > 0 {
- n -= 1;
- heap.sift_down(n);
- }
- heap
+ BinaryHeap::from(vec)
}
/// Returns an iterator visiting all values in the underlying vector, in
/// # Examples
///
/// ```
- /// #![feature(binary_heap_extras)]
- ///
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]);
+ /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]);
///
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.iter() {
/// # Examples
///
/// ```
- /// #![feature(binary_heap_extras)]
- ///
/// use std::collections::BinaryHeap;
- /// let mut heap = BinaryHeap::from_vec(vec![1, 3]);
+ /// let mut heap = BinaryHeap::from(vec![1, 3]);
///
/// assert_eq!(heap.pop(), Some(3));
/// assert_eq!(heap.pop(), Some(1));
/// # Examples
///
/// ```
- /// #![feature(binary_heap_extras)]
- ///
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4, 5, 6, 7]);
+ /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]);
/// let vec = heap.into_vec();
///
/// // Will print in some order
/// println!("{}", x);
/// }
/// ```
- #[unstable(feature = "binary_heap_extras",
- reason = "needs to be audited",
- issue = "28147")]
- pub fn into_vec(self) -> Vec<T> { self.data }
+ #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
+ pub fn into_vec(self) -> Vec<T> {
+ self.into()
+ }
/// Consumes the `BinaryHeap` and returns a vector in sorted
/// (ascending) order.
/// # Examples
///
/// ```
- /// #![feature(binary_heap_extras)]
- ///
/// use std::collections::BinaryHeap;
///
- /// let mut heap = BinaryHeap::from_vec(vec![1, 2, 4, 5, 7]);
+ /// let mut heap = BinaryHeap::from(vec![1, 2, 4, 5, 7]);
/// heap.push(6);
/// heap.push(3);
///
/// let vec = heap.into_sorted_vec();
/// assert_eq!(vec, [1, 2, 3, 4, 5, 6, 7]);
/// ```
- #[unstable(feature = "binary_heap_extras",
- reason = "needs to be audited",
- issue = "28147")]
+ #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
pub fn into_sorted_vec(mut self) -> Vec<T> {
let mut end = self.len();
while end > 1 {
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
+impl<T: Ord> From<Vec<T>> for BinaryHeap<T> {
+ fn from(vec: Vec<T>) -> BinaryHeap<T> {
+ let mut heap = BinaryHeap { data: vec };
+ let mut n = heap.len() / 2;
+ while n > 0 {
+ n -= 1;
+ heap.sift_down(n);
+ }
+ heap
+ }
+}
+
+impl<T> From<BinaryHeap<T>> for Vec<T> {
+ fn from(heap: BinaryHeap<T>) -> Vec<T> {
+ heap.data
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> FromIterator<T> for BinaryHeap<T> {
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> BinaryHeap<T> {
- BinaryHeap::from_vec(iter.into_iter().collect())
+ BinaryHeap::from(iter.into_iter().collect::<Vec<_>>())
}
}
/// # Examples
///
/// ```
- /// #![feature(binary_heap_extras)]
- ///
/// use std::collections::BinaryHeap;
- /// let heap = BinaryHeap::from_vec(vec![1, 2, 3, 4]);
+ /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]);
///
/// // Print 1, 2, 3, 4 in arbitrary order
/// for x in heap.into_iter() {
// 2) While ODS may potentially return the pair we *just* inserted after
// the split, we will never do this. Again, this shouldn't effect the analysis.
- /// Inserts a key-value pair into the map. If the key already had a value
- /// present in the map, that value is returned. Otherwise, `None` is returned.
+ /// Inserts a key-value pair into the map.
+ ///
+ /// If the map did not have this key present, `None` is returned.
+ ///
+ /// If the map did have this key present, that value is returned, and the
+ /// entry is not updated. See the [module-level documentation] for more.
+ ///
+ /// [module-level documentation]: index.html#insert-and-complex-keys
///
/// # Examples
///
top: node::Handle<*mut Node<K, V>, Type, NodeType>,
}
- /// A `PartialSearchStack` that doesn't hold a a reference to the next node, and is just
+ /// A `PartialSearchStack` that doesn't hold a reference to the next node, and is just
/// just waiting for a `Handle` to that next node to be pushed. See `PartialSearchStack::with`
/// for more details.
pub struct Pusher<'id, 'a, K:'a, V:'a> {
}
}
-/// Genericises over how to get the correct type of iterator from the correct type
+/// Genericizes over how to get the correct type of iterator from the correct type
/// of Node ownership.
trait Traverse<N> {
fn traverse(node: N) -> Self;
let (keys_size, keys_align) = (capacity * mem::size_of::<K>(), mem::align_of::<K>());
let (vals_size, vals_align) = (capacity * mem::size_of::<V>(), mem::align_of::<V>());
let (edges_size, edges_align) = if is_leaf {
- (0, 1)
+ // allocate one edge to ensure that we don't pass size 0 to `heap::allocate`
+ if mem::size_of::<K>() == 0 && mem::size_of::<V>() == 0 {
+ (1, mem::align_of::<Node<K, V>>())
+ } else {
+ (0, 1)
+ }
} else {
((capacity + 1) * mem::size_of::<Node<K, V>>(), mem::align_of::<Node<K, V>>())
};
}
impl<T> Drop for RawItems<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
- for _ in self.by_ref() {}
+ for _ in self {}
}
}
impl<K, V> Drop for Node<K, V> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
if self.keys.is_null() ||
(unsafe { self.keys.get() as *const K as usize == mem::POST_DROP_USIZE })
}
}
- /// Handle an underflow in this node's child. We favour handling "to the left" because we know
+ /// Handle an underflow in this node's child. We favor handling "to the left" because we know
/// we're empty, but our neighbour can be full. Handling to the left means when we choose to
/// steal, we pop off the end of our neighbour (always fast) and "unshift" ourselves
/// (always slow, but at least faster since we know we're half-empty).
}
impl<K, V> Drop for MoveTraversalImpl<K, V> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
// We need to cleanup the stored values manually, as the RawItems destructor would run
// after our deallocation.
other.is_subset(self)
}
- /// Adds a value to the set. Returns `true` if the value was not already
- /// present in the set.
+ /// Adds a value to the set.
+ ///
+ /// If the set did not have a value present, `true` is returned.
+ ///
+ /// If the set did have this key present, that value is returned, and the
+ /// entry is not updated. See the [module-level documentation] for more.
+ ///
+ /// [module-level documentation]: index.html#insert-and-complex-keys
///
/// # Examples
///
#[stable(feature = "rust1", since = "1.0.0")]
impl<E:CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(fmt, "{{"));
- let mut first = true;
- for e in self {
- if !first {
- try!(write!(fmt, ", "));
- }
- try!(write!(fmt, "{:?}", e));
- first = false;
- }
- write!(fmt, "}}")
+ fmt.debug_set().entries(self).finish()
}
}
//! }
//! ```
//!
-//! ### fmt::Display vs fmt::Debug
+//! ### `fmt::Display` vs `fmt::Debug`
//!
//! These two formatting traits have distinct purposes:
//!
//! to ensure padding is applied is to format your input, then use this
//! resulting string to pad your output.
//!
-//! ## Sign/#/0
+//! ## Sign/`#`/`0`
//!
//! These can all be interpreted as flags for a particular formatter.
//!
-//! * '+' - This is intended for numeric types and indicates that the sign
+//! * `+` - This is intended for numeric types and indicates that the sign
//! should always be printed. Positive signs are never printed by
//! default, and the negative sign is only printed by default for the
-//! `Signed` trait. This flag indicates that the correct sign (+ or -)
+//! `Signed` trait. This flag indicates that the correct sign (`+` or `-`)
//! should always be printed.
-//! * '-' - Currently not used
-//! * '#' - This flag is indicates that the "alternate" form of printing should
+//! * `-` - Currently not used
+//! * `#` - This flag is indicates that the "alternate" form of printing should
//! be used. The alternate forms are:
//! * `#?` - pretty-print the `Debug` formatting
-//! * `#x` - precedes the argument with a "0x"
-//! * `#X` - precedes the argument with a "0x"
-//! * `#b` - precedes the argument with a "0b"
-//! * `#o` - precedes the argument with a "0o"
-//! * '0' - This is used to indicate for integer formats that the padding should
+//! * `#x` - precedes the argument with a `0x`
+//! * `#X` - precedes the argument with a `0x`
+//! * `#b` - precedes the argument with a `0b`
+//! * `#o` - precedes the argument with a `0o`
+//! * `0` - This is used to indicate for integer formats that the padding should
//! both be done with a `0` character as well as be sign-aware. A format
//! like `{:08}` would yield `00000001` for the integer `1`, while the
//! same format would yield `-0000001` for the integer `-1`. Notice that
//!
//! The default fill/alignment for non-numerics is a space and left-aligned. The
//! defaults for numeric formatters is also a space but with right-alignment. If
-//! the '0' flag is specified for numerics, then the implicit fill character is
-//! '0'.
+//! the `0` flag is specified for numerics, then the implicit fill character is
+//! `0`.
//!
//! The value for the width can also be provided as a `usize` in the list of
//! parameters by using the `2$` syntax indicating that the second argument is a
#![allow(trivial_casts)]
#![cfg_attr(test, allow(deprecated))] // rand
+// SNAP 1af31d4
+#![allow(unused_features)]
+// SNAP 1af31d4
+#![allow(unused_attributes)]
+
#![feature(alloc)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(core_intrinsics)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
+#![feature(fmt_internals)]
+#![feature(fmt_radix)]
#![feature(heap_api)]
-#![feature(iter_order)]
#![feature(iter_arith)]
#![feature(iter_arith)]
#![feature(lang_items)]
#![feature(oom)]
#![feature(pattern)]
#![feature(ptr_as_ref)]
+#![feature(ref_slice)]
+#![feature(slice_bytes)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(step_by)]
#![feature(str_char)]
-#![feature(str_match_indices)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unique)]
+#![feature(dropck_parametricity)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(decode_utf16)]
-#![feature(utf8_error)]
-#![cfg_attr(test, feature(rand, test))]
+#![cfg_attr(test, feature(clone_from_slice, rand, test))]
#![feature(no_std)]
#![no_std]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for LinkedList<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
// Dissolve the linked_list in a loop.
// Just dropping the list_head can lead to stack exhaustion
pub use core::slice::{Iter, IterMut};
pub use core::slice::{SplitMut, ChunksMut, Split};
pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
+#[allow(deprecated)]
pub use core::slice::{bytes, mut_ref_slice, ref_slice};
pub use core::slice::{from_raw_parts, from_raw_parts_mut};
}
/// Returns the first and all the rest of the elements of a slice.
- #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")]
+ #[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_first(&self) -> Option<(&T, &[T])> {
core_slice::SliceExt::split_first(self)
}
/// Returns the first and all the rest of the elements of a slice.
- #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")]
+ #[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> {
core_slice::SliceExt::split_first_mut(self)
}
/// Returns the last and all the rest of the elements of a slice.
- #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")]
+ #[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_last(&self) -> Option<(&T, &[T])> {
core_slice::SliceExt::split_last(self)
}
/// Returns the last and all the rest of the elements of a slice.
- #[unstable(feature = "slice_splits", reason = "new API", issue = "27742")]
+ #[stable(feature = "slice_splits", since = "1.5.0")]
#[inline]
pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> {
core_slice::SliceExt::split_last_mut(self)
/// the index `mid` itself) and the second will contain all
/// indices from `[mid, len)` (excluding the index `len` itself).
///
+ /// # Panics
+ ///
/// Panics if `mid > len`.
///
/// # Examples
use boxed::Box;
pub use core::str::{FromStr, Utf8Error};
+#[allow(deprecated)]
pub use core::str::{Lines, LinesAny, CharRange};
pub use core::str::{Split, RSplit};
pub use core::str::{SplitN, RSplitN};
}
}
-/// External iterator for a string's UTF16 codeunits.
+/// External iterator for a string's UTF-16 code units.
///
/// For use with the `std::iter` module.
#[derive(Clone)]
///
/// Returns the substring from [`begin`..`end`).
///
- /// # Unsafety
+ /// # Safety
///
/// Caller must check both UTF-8 sequence boundaries and the boundaries
/// of the entire slice as well.
/// Takes a bytewise mutable slice from a string.
///
/// Same as `slice_unchecked`, but works with `&mut str` instead of `&str`.
- #[unstable(feature = "str_slice_mut", reason = "recently added",
- issue = "27793")]
+ #[stable(feature = "str_slice_mut", since = "1.5.0")]
#[inline]
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
core_str::StrExt::slice_mut_unchecked(self, begin, end)
///
/// # Examples
/// ```
- /// #![feature(str_split_at)]
- ///
/// let s = "Löwe 老虎 Léopard";
/// let first_space = s.find(' ').unwrap_or(s.len());
/// let (a, b) = s.split_at(first_space);
/// Returns `None` if it doesn't exist.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the
- /// split.
+ /// determines if a character matches.
///
/// # Examples
///
/// Returns `None` if it doesn't exist.
///
/// The pattern can be a simple `&str`, `char`,
- /// or a closure that determines the split.
+ /// or a closure that determines if a character matches.
///
/// # Examples
///
/// ```rust,ignore
/// assert_eq!(d, &["a", "b", "c"]);
/// ```
+ ///
+ /// Use [`.split_whitespace()`][split_whitespace] for this behavior.
+ ///
+ /// [split_whitespace]: #method.split_whitespace
#[stable(feature = "rust1", since = "1.0.0")]
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
core_str::StrExt::split(self, pat)
/// An iterator over the matches of a pattern within `self`.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
+ /// determines if a character matches.
/// Additional libraries might provide more complex patterns like
/// regular expressions.
///
/// reverse order.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
+ /// determines if a character matches.
/// Additional libraries might provide more complex patterns like
/// regular expressions.
///
core_str::StrExt::rmatches(self, pat)
}
- /// An iterator over the start and end indices of the disjoint matches
- /// of a pattern within `self`.
+ /// An iterator over the disjoint matches of a pattern within `self` as well
+ /// as the index that the match starts at.
///
/// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the first
- /// match are returned.
+ /// corresponding to the first match are returned.
///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines
- /// the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
+ /// The pattern can be a simple `&str`, `char`, or a closure that determines
+ /// if a character matches. Additional libraries might provide more complex
+ /// patterns like regular expressions.
///
/// # Iterator behavior
///
/// The returned iterator will be double ended if the pattern allows a
- /// reverse search
- /// and forward/reverse search yields the same elements. This is true for,
- /// eg, `char` but not
- /// for `&str`.
+ /// reverse search and forward/reverse search yields the same elements. This
+ /// is true for, eg, `char` but not for `&str`.
///
/// If the pattern allows a reverse search but its results might differ
/// from a forward search, `rmatch_indices()` can be used.
/// ```
/// #![feature(str_match_indices)]
///
- /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".match_indices("abc").collect();
- /// assert_eq!(v, [(0, 3), (6, 9), (12, 15)]);
+ /// let v: Vec<_> = "abcXXXabcYYYabc".match_indices("abc").collect();
+ /// assert_eq!(v, [(0, "abc"), (6, "abc"), (12, "abc")]);
///
- /// let v: Vec<(usize, usize)> = "1abcabc2".match_indices("abc").collect();
- /// assert_eq!(v, [(1, 4), (4, 7)]);
+ /// let v: Vec<_> = "1abcabc2".match_indices("abc").collect();
+ /// assert_eq!(v, [(1, "abc"), (4, "abc")]);
///
- /// let v: Vec<(usize, usize)> = "ababa".match_indices("aba").collect();
- /// assert_eq!(v, [(0, 3)]); // only the first `aba`
+ /// let v: Vec<_> = "ababa".match_indices("aba").collect();
+ /// assert_eq!(v, [(0, "aba")]); // only the first `aba`
/// ```
- #[unstable(feature = "str_match_indices",
- reason = "might have its iterator type changed",
- issue = "27743")]
- // NB: Right now MatchIndices yields `(usize, usize)`, but it would
- // be more consistent with `matches` and `char_indices` to return `(usize, &str)`
+ #[stable(feature = "str_match_indices", since = "1.5.0")]
pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
core_str::StrExt::match_indices(self, pat)
}
- /// An iterator over the start and end indices of the disjoint matches of
- /// a pattern within
- /// `self`, yielded in reverse order.
+ /// An iterator over the disjoint matches of a pattern within `self`,
+ /// yielded in reverse order along with the index of the match.
///
/// For matches of `pat` within `self` that overlap, only the indices
- /// corresponding to the last
- /// match are returned.
+ /// corresponding to the last match are returned.
///
- /// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines
- /// the split.
- /// Additional libraries might provide more complex patterns like
- /// regular expressions.
+ /// The pattern can be a simple `&str`, `char`, or a closure that determines
+ /// if a character matches. Additional libraries might provide more complex
+ /// patterns like regular expressions.
///
/// # Iterator behavior
///
- /// The returned iterator requires that the pattern supports a
- /// reverse search,
- /// and it will be double ended if a forward/reverse search yields
+ /// The returned iterator requires that the pattern supports a reverse
+ /// search, and it will be double ended if a forward/reverse search yields
/// the same elements.
///
/// For iterating from the front, `match_indices()` can be used.
/// ```
/// #![feature(str_match_indices)]
///
- /// let v: Vec<(usize, usize)> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(12, 15), (6, 9), (0, 3)]);
+ /// let v: Vec<_> = "abcXXXabcYYYabc".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(12, "abc"), (6, "abc"), (0, "abc")]);
///
- /// let v: Vec<(usize, usize)> = "1abcabc2".rmatch_indices("abc").collect();
- /// assert_eq!(v, [(4, 7), (1, 4)]);
+ /// let v: Vec<_> = "1abcabc2".rmatch_indices("abc").collect();
+ /// assert_eq!(v, [(4, "abc"), (1, "abc")]);
///
- /// let v: Vec<(usize, usize)> = "ababa".rmatch_indices("aba").collect();
- /// assert_eq!(v, [(2, 5)]); // only the last `aba`
+ /// let v: Vec<_> = "ababa".rmatch_indices("aba").collect();
+ /// assert_eq!(v, [(2, "aba")]); // only the last `aba`
/// ```
- #[unstable(feature = "str_match_indices",
- reason = "might have its iterator type changed",
- issue = "27743")]
- // NB: Right now RMatchIndices yields `(usize, usize)`, but it would
- // be more consistent with `rmatches` and `char_indices` to return `(usize, &str)`
+ #[stable(feature = "str_match_indices", since = "1.5.0")]
pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
/// repeatedly removed.
///
/// The pattern can be a simple `char`, or a closure that determines
- /// the split.
+ /// if a character matches.
///
/// # Examples
///
/// repeatedly removed.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
+ /// determines if a character matches.
///
/// # Examples
///
/// repeatedly removed.
///
/// The pattern can be a simple `&str`, `char`, or a closure that
- /// determines the split.
+ /// determines if a character matches.
///
/// # Examples
///
pub fn replace(&self, from: &str, to: &str) -> String {
let mut result = String::new();
let mut last_end = 0;
- for (start, end) in self.match_indices(from) {
+ for (start, part) in self.match_indices(from) {
result.push_str(unsafe { self.slice_unchecked(last_end, start) });
result.push_str(to);
- last_end = end;
+ last_end = start + part.len();
}
result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) });
result
use boxed::Box;
/// A growable string stored as a UTF-8 encoded buffer.
-#[derive(Clone, PartialOrd, Eq, Ord)]
+#[derive(PartialOrd, Eq, Ord)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct String {
vec: Vec<u8>,
panic!("not available with cfg(test)");
}
- /// Returns the vector as a string buffer, if possible, taking care not to
- /// copy it.
+ /// Converts a vector of bytes to a `String`.
+ ///
+ /// A string slice (`&str`) is made of bytes (`u8`), and a vector of bytes
+ /// (`Vec<u8>`) is made of bytes, so this function converts between the
+ /// two. Not all byte slices are valid `String`s, however: `String`
+ /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that
+ /// the bytes are valid UTF-8, and then does the conversion.
+ ///
+ /// If you are sure that the byte slice is valid UTF-8, and you don't want
+ /// to incur the overhead of the validity check, there is an unsafe version
+ /// of this function, [`from_utf8_unchecked()`][fromutf8], which has the
+ /// same behavior but skips the check.
+ ///
+ /// [fromutf8]: struct.String.html#method.from_utf8_unchecked
+ ///
+ /// This method will take care to not copy the vector, for efficiency's
+ /// sake.
+ ///
+ /// If you need a `&str` instead of a `String`, consider
+ /// [`str::from_utf8()`][str].
+ ///
+ /// [str]: ../str/fn.from_utf8.html
///
/// # Failure
///
- /// If the given vector is not valid UTF-8, then the original vector and the
- /// corresponding error is returned.
+ /// Returns `Err` if the slice is not UTF-8 with a description as to why the
+ /// provided bytes are not UTF-8. The vector you moved in is also included.
///
/// # Examples
///
+ /// Basic usage:
+ ///
/// ```
- /// let hello_vec = vec![104, 101, 108, 108, 111];
- /// let s = String::from_utf8(hello_vec).unwrap();
- /// assert_eq!(s, "hello");
- ///
- /// let invalid_vec = vec![240, 144, 128];
- /// let s = String::from_utf8(invalid_vec).err().unwrap();
- /// let err = s.utf8_error();
- /// assert_eq!(s.into_bytes(), [240, 144, 128]);
+ /// // some bytes, in a vector
+ /// let sparkle_heart = vec![240, 159, 146, 150];
+ ///
+ /// // We know these bytes are valid, so just use `unwrap()`.
+ /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();
+ ///
+ /// assert_eq!("💖", sparkle_heart);
+ /// ```
+ ///
+ /// Incorrect bytes:
+ ///
/// ```
+ /// // some invalid bytes, in a vector
+ /// let sparkle_heart = vec![0, 159, 146, 150];
+ ///
+ /// assert!(String::from_utf8(sparkle_heart).is_err());
+ /// ```
+ ///
+ /// See the docs for [`FromUtf8Error`][error] for more details on what you
+ /// can do with this error.
+ ///
+ /// [error]: struct.FromUtf8Error.html
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
}
}
- /// Converts a vector of bytes to a new UTF-8 string.
- /// Any invalid UTF-8 sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
+ /// Converts a slice of bytes to a `String`, including invalid characters.
+ ///
+ /// A string slice (`&str`) is made of bytes (`u8`), and a slice of bytes
+ /// (`&[u8]`) is made of bytes, so this function converts between the two.
+ /// Not all byte slices are valid string slices, however: `&str` requires
+ /// that it is valid UTF-8. During this conversion, `from_utf8_lossy()`
+ /// will replace any invalid UTF-8 sequences with
+ /// `U+FFFD REPLACEMENT CHARACTER`, which looks like this: �
+ ///
+ /// If you are sure that the byte slice is valid UTF-8, and you don't want
+ /// to incur the overhead of the conversion, there is an unsafe version
+ /// of this function, [`from_utf8_unchecked()`][fromutf8], which has the
+ /// same behavior but skips the checks.
+ ///
+ /// [fromutf8]: struct.String.html#method.from_utf8_unchecked
+ ///
+ /// If you need a `&str` instead of a `String`, consider
+ /// [`str::from_utf8()`][str].
+ ///
+ /// [str]: ../str/fn.from_utf8.html
///
/// # Examples
///
+ /// Basic usage:
+ ///
/// ```
+ /// // some bytes, in a vector
+ /// let sparkle_heart = vec![240, 159, 146, 150];
+ ///
+ /// // We know these bytes are valid, so just use `unwrap()`.
+ /// let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();
+ ///
+ /// assert_eq!("💖", sparkle_heart);
+ /// ```
+ ///
+ /// Incorrect bytes:
+ ///
+ /// ```
+ /// // some invalid bytes
/// let input = b"Hello \xF0\x90\x80World";
/// let output = String::from_utf8_lossy(input);
- /// assert_eq!(output, "Hello \u{FFFD}World");
+ ///
+ /// assert_eq!("Hello �World", output);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8_lossy<'a>(v: &'a [u8]) -> Cow<'a, str> {
/// Creates a new `String` from a length, capacity, and pointer.
///
- /// # Unsafety
+ /// # Safety
///
/// This is _very_ unsafe because:
///
}
}
- /// Converts a vector of bytes to a new `String` without checking if
- /// it contains valid UTF-8. This is unsafe because it assumes that
- /// the UTF-8-ness of the vector has already been validated.
+ /// Converts a vector of bytes to a `String` without checking that the
+ /// string contains valid UTF-8.
+ ///
+ /// See the safe version, [`from_utf8()`][fromutf8], for more.
+ ///
+ /// [fromutf8]: struct.String.html#method.from_utf8
+ ///
+ /// # Safety
+ ///
+ /// This function is unsafe because it does not check that the bytes passed to
+ /// it are valid UTF-8. If this constraint is violated, undefined behavior
+ /// results, as the rest of Rust assumes that `String`s are valid UTF-8.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// // some bytes, in a vector
+ /// let sparkle_heart = vec![240, 159, 146, 150];
+ ///
+ /// let sparkle_heart = unsafe {
+ /// String::from_utf8_unchecked(sparkle_heart)
+ /// };
+ ///
+ /// assert_eq!("💖", sparkle_heart);
+ /// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_utf8_unchecked(bytes: Vec<u8>) -> String {
}
}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Clone for String {
+ fn clone(&self) -> Self {
+ String { vec: self.vec.clone() }
+ }
+
+ fn clone_from(&mut self, source: &Self) {
+ self.vec.clone_from(&source.vec);
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl FromIterator<char> for String {
fn from_iter<I: IntoIterator<Item=char>>(iterable: I) -> String {
}
/// Error returned from `String::from`
-#[unstable(feature = "str_parse_error", reason = "may want to be replaced with \
- Void if it ever exists",
- issue = "27734")]
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct ParseError(());
+#[stable(feature = "str_parse_error", since = "1.5.0")]
+#[derive(Copy)]
+pub enum ParseError {}
#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for String {
}
}
+impl Clone for ParseError {
+ fn clone(&self) -> ParseError {
+ match *self {}
+ }
+}
+
+impl fmt::Debug for ParseError {
+ fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
+ match *self {}
+ }
+}
+
+impl PartialEq for ParseError {
+ fn eq(&self, _: &ParseError) -> bool {
+ match *self {}
+ }
+}
+
+impl Eq for ParseError {}
+
/// A generic trait for converting a value to a string
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ToString {
use core::cmp::Ordering;
use core::fmt;
use core::hash::{self, Hash};
-use core::intrinsics::{arith_offset, assume, drop_in_place};
+use core::intrinsics::{arith_offset, assume, drop_in_place, needs_drop};
use core::iter::FromIterator;
use core::mem;
use core::ops::{Index, IndexMut, Deref};
/// if the vector's length is increased to 11, it will have to reallocate, which
/// can be slow. For this reason, it is recommended to use `Vec::with_capacity`
/// whenever possible to specify how big the vector is expected to get.
+///
+/// # Guarantees
+///
+/// Due to its incredibly fundamental nature, Vec makes a lot of guarantees
+/// about its design. This ensures that it's as low-overhead as possible in
+/// the general case, and can be correctly manipulated in primitive ways
+/// by unsafe code. Note that these guarantees refer to an unqualified `Vec<T>`.
+/// If additional type parameters are added (e.g. to support custom allocators),
+/// overriding their defaults may change the behavior.
+///
+/// Most fundamentally, Vec is and always will be a (pointer, capacity, length)
+/// triplet. No more, no less. The order of these fields is completely
+/// unspecified, and you should use the appropriate methods to modify these.
+/// The pointer will never be null, so this type is null-pointer-optimized.
+///
+/// However, the pointer may not actually point to allocated memory. In particular,
+/// if you construct a Vec with capacity 0 via `Vec::new()`, `vec![]`,
+/// `Vec::with_capacity(0)`, or by calling `shrink_to_fit()` on an empty Vec, it
+/// will not allocate memory. Similarly, if you store zero-sized types inside
+/// a Vec, it will not allocate space for them. *Note that in this case the
+/// Vec may not report a `capacity()` of 0*. Vec will allocate if and only
+/// if `mem::size_of::<T>() * capacity() > 0`. In general, Vec's allocation
+/// details are subtle enough that it is strongly recommended that you only
+/// free memory allocated by a Vec by creating a new Vec and dropping it.
+///
+/// If a Vec *has* allocated memory, then the memory it points to is on the heap
+/// (as defined by the allocator Rust is configured to use by default), and its
+/// pointer points to `len()` initialized elements in order (what you would see
+/// if you coerced it to a slice), followed by `capacity() - len()` logically
+/// uninitialized elements.
+///
+/// Vec will never perform a "small optimization" where elements are actually
+/// stored on the stack for two reasons:
+///
+/// * It would make it more difficult for unsafe code to correctly manipulate
+/// a Vec. The contents of a Vec wouldn't have a stable address if it were
+/// only moved, and it would be more difficult to determine if a Vec had
+/// actually allocated memory.
+///
+/// * It would penalize the general case, incurring an additional branch
+/// on every access.
+///
+/// Vec will never automatically shrink itself, even if completely empty. This
+/// ensures no unnecessary allocations or deallocations occur. Emptying a Vec
+/// and then filling it back up to the same `len()` should incur no calls to
+/// the allocator. If you wish to free up unused memory, use `shrink_to_fit`.
+///
+/// `push` and `insert` will never (re)allocate if the reported capacity is
+/// sufficient. `push` and `insert` *will* (re)allocate if `len() == capacity()`.
+/// That is, the reported capacity is completely accurate, and can be relied on.
+/// It can even be used to manually free the memory allocated by a Vec if
+/// desired. Bulk insertion methods *may* reallocate, even when not necessary.
+///
+/// Vec does not guarantee any particular growth strategy when reallocating
+/// when full, nor when `reserve` is called. The current strategy is basic
+/// and it may prove desirable to use a non-constant growth factor. Whatever
+/// strategy is used will of course guarantee `O(1)` amortized `push`.
+///
+/// `vec![x; n]`, `vec![a, b, c, d]`, and `Vec::with_capacity(n)`, will all
+/// produce a Vec with exactly the requested capacity. If `len() == capacity()`,
+/// (as is the case for the `vec!` macro), then a `Vec<T>` can be converted
+/// to and from a `Box<[T]>` without reallocating or moving the elements.
+///
+/// Vec will not specifically overwrite any data that is removed from it,
+/// but also won't specifically preserve it. Its uninitialized memory is
+/// scratch space that it may use however it wants. It will generally just do
+/// whatever is most efficient or otherwise easy to implement. Do not rely on
+/// removed data to be erased for security purposes. Even if you drop a Vec, its
+/// buffer may simply be reused by another Vec. Even if you zero a Vec's memory
+/// first, that may not actually happen because the optimizer does not consider
+/// this a side-effect that must be preserved.
+///
+/// Vec does not currently guarantee the order in which elements are dropped
+/// (the order has changed in the past, and may change again).
+///
#[unsafe_no_drop_flag]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Vec<T> {
/// Creates a `Vec<T>` directly from the raw components of another vector.
///
- /// # Unsafety
+ /// # Safety
///
/// This is highly unsafe, due to the number of invariants that aren't
/// checked:
/// # Examples
///
/// ```
- /// #![feature(split_off)]
- ///
/// let mut vec = vec![1,2,3];
/// let vec2 = vec.split_off(1);
/// assert_eq!(vec, [1]);
/// # Examples
///
/// ```
- /// #![feature(vec_resize)]
- ///
/// let mut vec = vec!["hello"];
/// vec.resize(3, "world");
/// assert_eq!(vec, ["hello", "world", "world"]);
/// vec.resize(2, 0);
/// assert_eq!(vec, [1, 2]);
/// ```
- #[unstable(feature = "vec_resize",
- reason = "matches collection reform specification; waiting for dust to settle",
- issue = "27790")]
+ #[stable(feature = "vec_resize", since = "1.5.0")]
pub fn resize(&mut self, new_len: usize, value: T) {
let len = self.len();
fn clone_from(&mut self, other: &Vec<T>) {
// drop anything in self that will not be overwritten
- if self.len() > other.len() {
- self.truncate(other.len())
- }
+ self.truncate(other.len());
+ let len = self.len();
// reuse the contained values' allocations/resources.
- for (place, thing) in self.iter_mut().zip(other) {
- place.clone_from(thing)
- }
+ self.clone_from_slice(&other[..len]);
// self.len <= other.len due to the truncate above, so the
// slice here is always in-bounds.
- let slice = &other[self.len()..];
- self.push_all(slice);
+ self.push_all(&other[len..]);
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for Vec<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
// NOTE: this is currently abusing the fact that ZSTs can't impl Drop.
// Or rather, that impl'ing Drop makes them not zero-sized. This is
// OK because exactly when this stops being a valid assumption, we
// don't need unsafe_no_drop_flag shenanigans anymore.
if self.buf.unsafe_no_drop_flag_needs_drop() {
- for x in self.iter_mut() {
- unsafe { drop_in_place(x); }
+ unsafe {
+ // The branch on needs_drop() is an -O1 performance optimization.
+ // Without the branch, dropping Vec<u8> takes linear time.
+ if needs_drop::<T>() {
+ for x in self.iter_mut() {
+ drop_in_place(x);
+ }
+ }
}
}
// RawVec handles deallocation
}
}
+#[stable(feature = "vec_as_mut", since = "1.5.0")]
+impl<T> AsMut<Vec<T>> for Vec<T> {
+ fn as_mut(&mut self) -> &mut Vec<T> {
+ self
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> AsRef<[T]> for Vec<T> {
fn as_ref(&self) -> &[T] {
}
}
+#[stable(feature = "vec_as_mut", since = "1.5.0")]
+impl<T> AsMut<[T]> for Vec<T> {
+ fn as_mut(&mut self) -> &mut [T] {
+ self
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: Clone> From<&'a [T]> for Vec<T> {
#[cfg(not(test))]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for IntoIter<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
// destroy the remaining elements
- for _x in self.by_ref() {}
+ for _x in self {}
// RawVec handles deallocation
}
use alloc::raw_vec::RawVec;
+use super::range::RangeArgument;
+
const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
const MINIMUM_CAPACITY: usize = 1; // 2 - 1
const MAXIMUM_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); // Largest possible power of two
-/// `VecDeque` is a growable ring buffer, which can be used as a
-/// double-ended queue efficiently.
+/// `VecDeque` is a growable ring buffer, which can be used as a double-ended
+/// queue efficiently.
///
-/// The "default" usage of this type as a queue is to use `push_back` to add to the queue, and
-/// `pop_front` to remove from the queue. `extend` and `append` push onto the back in this manner,
-/// and iterating over `VecDeque` goes front to back.
+/// The "default" usage of this type as a queue is to use `push_back` to add to
+/// the queue, and `pop_front` to remove from the queue. `extend` and `append`
+/// push onto the back in this manner, and iterating over `VecDeque` goes front
+/// to back.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct VecDeque<T> {
// tail and head are pointers into the buffer. Tail always points
#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Drop for VecDeque<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
self.clear();
// RawVec handles deallocation
len);
}
+ /// Copies a potentially wrapping block of memory len long from src to dest.
+ /// (abs(dst - src) + len) must be no larger than cap() (There must be at
+ /// most one continuous overlapping region between src and dest).
+ unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) {
+ debug_assert!(
+ (if src <= dst { dst - src } else { src - dst }) + len <= self.cap(),
+ "dst={} src={} len={} cap={}", dst, src, len, self.cap());
+
+ if src == dst || len == 0 { return }
+
+ let dst_after_src = self.wrap_sub(dst, src) < len;
+
+ let src_pre_wrap_len = self.cap() - src;
+ let dst_pre_wrap_len = self.cap() - dst;
+ let src_wraps = src_pre_wrap_len < len;
+ let dst_wraps = dst_pre_wrap_len < len;
+
+ match (dst_after_src, src_wraps, dst_wraps) {
+ (_, false, false) => {
+ // src doesn't wrap, dst doesn't wrap
+ //
+ // S . . .
+ // 1 [_ _ A A B B C C _]
+ // 2 [_ _ A A A A B B _]
+ // D . . .
+ //
+ self.copy(dst, src, len);
+ }
+ (false, false, true) => {
+ // dst before src, src doesn't wrap, dst wraps
+ //
+ // S . . .
+ // 1 [A A B B _ _ _ C C]
+ // 2 [A A B B _ _ _ A A]
+ // 3 [B B B B _ _ _ A A]
+ // . . D .
+ //
+ self.copy(dst, src, dst_pre_wrap_len);
+ self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+ }
+ (true, false, true) => {
+ // src before dst, src doesn't wrap, dst wraps
+ //
+ // S . . .
+ // 1 [C C _ _ _ A A B B]
+ // 2 [B B _ _ _ A A B B]
+ // 3 [B B _ _ _ A A A A]
+ // . . D .
+ //
+ self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
+ self.copy(dst, src, dst_pre_wrap_len);
+ }
+ (false, true, false) => {
+ // dst before src, src wraps, dst doesn't wrap
+ //
+ // . . S .
+ // 1 [C C _ _ _ A A B B]
+ // 2 [C C _ _ _ B B B B]
+ // 3 [C C _ _ _ B B C C]
+ // D . . .
+ //
+ self.copy(dst, src, src_pre_wrap_len);
+ self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+ }
+ (true, true, false) => {
+ // src before dst, src wraps, dst doesn't wrap
+ //
+ // . . S .
+ // 1 [A A B B _ _ _ C C]
+ // 2 [A A A A _ _ _ C C]
+ // 3 [C C A A _ _ _ C C]
+ // D . . .
+ //
+ self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
+ self.copy(dst, src, src_pre_wrap_len);
+ }
+ (false, true, true) => {
+ // dst before src, src wraps, dst wraps
+ //
+ // . . . S .
+ // 1 [A B C D _ E F G H]
+ // 2 [A B C D _ E G H H]
+ // 3 [A B C D _ E G H A]
+ // 4 [B C C D _ E G H A]
+ // . . D . .
+ //
+ debug_assert!(dst_pre_wrap_len > src_pre_wrap_len);
+ let delta = dst_pre_wrap_len - src_pre_wrap_len;
+ self.copy(dst, src, src_pre_wrap_len);
+ self.copy(dst + src_pre_wrap_len, 0, delta);
+ self.copy(0, delta, len - dst_pre_wrap_len);
+ }
+ (true, true, true) => {
+ // src before dst, src wraps, dst wraps
+ //
+ // . . S . .
+ // 1 [A B C D _ E F G H]
+ // 2 [A A B D _ E F G H]
+ // 3 [H A B D _ E F G H]
+ // 4 [H A B D _ E F F G]
+ // . . . D .
+ //
+ debug_assert!(src_pre_wrap_len > dst_pre_wrap_len);
+ let delta = src_pre_wrap_len - dst_pre_wrap_len;
+ self.copy(delta, 0, len - src_pre_wrap_len);
+ self.copy(0, self.cap() - delta, delta);
+ self.copy(dst, src, dst_pre_wrap_len);
+ }
+ }
+ }
+
/// Frobs the head and tail sections around to handle the fact that we
/// just reallocated. Unsafe because it trusts old_cap.
#[inline]
/// # Examples
///
/// ```
- /// #![feature(deque_extras)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::with_capacity(15);
/// buf.shrink_to_fit();
/// assert!(buf.capacity() >= 4);
/// ```
- #[unstable(feature = "deque_extras",
- reason = "needs to be audited",
- issue = "27788")]
+ #[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn shrink_to_fit(&mut self) {
// +1 since the ringbuffer always leaves one space empty
// len + 1 can't overflow for an existing, well-formed ringbuffer.
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
#[inline]
- #[unstable(feature = "deque_extras",
- reason = "matches collection reform specification, waiting for dust to settle",
- issue = "27788")]
+ #[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn as_slices(&self) -> (&[T], &[T]) {
unsafe {
let contiguous = self.is_contiguous();
/// Returns a pair of slices which contain, in order, the contents of the
/// `VecDeque`.
#[inline]
- #[unstable(feature = "deque_extras",
- reason = "matches collection reform specification, waiting for dust to settle",
- issue = "27788")]
+ #[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
unsafe {
let contiguous = self.is_contiguous();
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_empty(&self) -> bool { self.len() == 0 }
- /// Creates a draining iterator that clears the `VecDeque` and iterates over
- /// the removed items from start to end.
+ /// Create a draining iterator that removes the specified range in the
+ /// `VecDeque` and yields the removed items from start to end. The element
+ /// range is removed even if the iterator is not consumed until the end.
+ ///
+ /// Note: It is unspecified how many elements are removed from the deque,
+ /// if the `Drain` value is not dropped, but the borrow it holds expires
+ /// (eg. due to mem::forget).
+ ///
+ /// # Panics
+ ///
+ /// Panics if the starting point is greater than the end point or if
+ /// the end point is greater than the length of the vector.
///
/// # Examples
///
///
/// use std::collections::VecDeque;
///
+ /// // draining using `..` clears the whole deque.
/// let mut v = VecDeque::new();
/// v.push_back(1);
- /// assert_eq!(v.drain().next(), Some(1));
+ /// assert_eq!(v.drain(..).next(), Some(1));
/// assert!(v.is_empty());
/// ```
#[inline]
#[unstable(feature = "drain",
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27711")]
- pub fn drain(&mut self) -> Drain<T> {
+ pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
+ // Memory safety
+ //
+ // When the Drain is first created, the source deque is shortened to
+ // make sure no uninitialized or moved-from elements are accessible at
+ // all if the Drain's destructor never gets to run.
+ //
+ // Drain will ptr::read out the values to remove.
+ // When finished, the remaining data will be copied back to cover the hole,
+ // and the head/tail values will be restored correctly.
+ //
+ let len = self.len();
+ let start = *range.start().unwrap_or(&0);
+ let end = *range.end().unwrap_or(&len);
+ assert!(start <= end, "drain lower bound was too large");
+ assert!(end <= len, "drain upper bound was too large");
+
+ // The deque's elements are parted into three segments:
+ // * self.tail -> drain_tail
+ // * drain_tail -> drain_head
+ // * drain_head -> self.head
+ //
+ // T = self.tail; H = self.head; t = drain_tail; h = drain_head
+ //
+ // We store drain_tail as self.head, and drain_head and self.head as
+ // after_tail and after_head respectively on the Drain. This also
+ // truncates the effective array such that if the Drain is leaked, we
+ // have forgotten about the potentially moved values after the start of
+ // the drain.
+ //
+ // T t h H
+ // [. . . o o x x o o . . .]
+ //
+ let drain_tail = self.wrap_add(self.tail, start);
+ let drain_head = self.wrap_add(self.tail, end);
+ let head = self.head;
+
+ // "forget" about the values after the start of the drain until after
+ // the drain is complete and the Drain destructor is run.
+ self.head = drain_tail;
+
Drain {
- inner: self,
+ deque: self as *mut _,
+ after_tail: drain_head,
+ after_head: head,
+ iter: Iter {
+ tail: drain_tail,
+ head: drain_head,
+ ring: unsafe { self.buffer_as_mut_slice() },
+ },
}
}
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn clear(&mut self) {
- self.drain();
+ self.drain(..);
}
/// Provides a reference to the front element, or `None` if the sequence is
/// # Examples
///
/// ```
- /// #![feature(deque_extras)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
- /// assert_eq!(buf.swap_back_remove(0), None);
+ /// assert_eq!(buf.swap_remove_back(0), None);
/// buf.push_back(1);
/// buf.push_back(2);
/// buf.push_back(3);
///
- /// assert_eq!(buf.swap_back_remove(0), Some(1));
+ /// assert_eq!(buf.swap_remove_back(0), Some(1));
/// assert_eq!(buf.len(), 2);
/// assert_eq!(buf[0], 3);
/// assert_eq!(buf[1], 2);
/// ```
- #[unstable(feature = "deque_extras",
- reason = "the naming of this function may be altered",
- issue = "27788")]
- pub fn swap_back_remove(&mut self, index: usize) -> Option<T> {
+ #[stable(feature = "deque_extras_15", since = "1.5.0")]
+ pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
let length = self.len();
if length > 0 && index < length - 1 {
self.swap(index, length - 1);
self.pop_back()
}
+ /// deprecated
+ #[unstable(feature = "deque_extras",
+ reason = "the naming of this function may be altered",
+ issue = "27788")]
+ #[deprecated(since = "1.5.0", reason = "renamed to swap_remove_back")]
+ pub fn swap_back_remove(&mut self, index: usize) -> Option<T> {
+ self.swap_remove_back(index)
+ }
+
/// Removes an element from anywhere in the `VecDeque` and returns it,
/// replacing it with the first element.
///
/// # Examples
///
/// ```
- /// #![feature(deque_extras)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
- /// assert_eq!(buf.swap_front_remove(0), None);
+ /// assert_eq!(buf.swap_remove_front(0), None);
/// buf.push_back(1);
/// buf.push_back(2);
/// buf.push_back(3);
///
- /// assert_eq!(buf.swap_front_remove(2), Some(3));
+ /// assert_eq!(buf.swap_remove_front(2), Some(3));
/// assert_eq!(buf.len(), 2);
/// assert_eq!(buf[0], 2);
/// assert_eq!(buf[1], 1);
/// ```
- #[unstable(feature = "deque_extras",
- reason = "the naming of this function may be altered",
- issue = "27788")]
- pub fn swap_front_remove(&mut self, index: usize) -> Option<T> {
+ #[stable(feature = "deque_extras_15", since = "1.5.0")]
+ pub fn swap_remove_front(&mut self, index: usize) -> Option<T> {
let length = self.len();
if length > 0 && index < length && index != 0 {
self.swap(index, 0);
self.pop_front()
}
+ /// deprecated
+ #[unstable(feature = "deque_extras",
+ reason = "the naming of this function may be altered",
+ issue = "27788")]
+ #[deprecated(since = "1.5.0", reason = "renamed to swap_remove_front")]
+ pub fn swap_front_remove(&mut self, index: usize) -> Option<T> {
+ self.swap_remove_front(index)
+ }
+
/// Inserts an element at `index` within the `VecDeque`. Whichever
/// end is closer to the insertion point will be moved to make room,
/// and all the affected elements will be moved to new positions.
///
/// # Examples
/// ```
- /// #![feature(deque_extras)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
/// buf.insert(1, 11);
/// assert_eq!(Some(&11), buf.get(1));
/// ```
- #[unstable(feature = "deque_extras",
- reason = "needs to be audited",
- issue = "27788")]
+ #[stable(feature = "deque_extras_15", since = "1.5.0")]
pub fn insert(&mut self, index: usize, value: T) {
assert!(index <= self.len(), "index out of bounds");
if self.is_full() {
/// # Examples
///
/// ```
- /// #![feature(split_off)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf: VecDeque<_> = vec![1,2,3].into_iter().collect();
#[stable(feature = "append", since = "1.4.0")]
pub fn append(&mut self, other: &mut Self) {
// naive impl
- self.extend(other.drain());
+ self.extend(other.drain(..));
}
/// Retains only the elements specified by the predicate.
/// # Examples
///
/// ```
- /// #![feature(vec_deque_retain)]
- ///
/// use std::collections::VecDeque;
///
/// let mut buf = VecDeque::new();
reason = "matches collection reform specification, waiting for dust to settle",
issue = "27711")]
pub struct Drain<'a, T: 'a> {
- inner: &'a mut VecDeque<T>,
+ after_tail: usize,
+ after_head: usize,
+ iter: Iter<'a, T>,
+ deque: *mut VecDeque<T>,
}
+unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
+unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: 'a> Drop for Drain<'a, T> {
fn drop(&mut self) {
for _ in self.by_ref() {}
- self.inner.head = 0;
- self.inner.tail = 0;
+
+ let source_deque = unsafe { &mut *self.deque };
+
+ // T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
+ //
+ // T t h H
+ // [. . . o o x x o o . . .]
+ //
+ let orig_tail = source_deque.tail;
+ let drain_tail = source_deque.head;
+ let drain_head = self.after_tail;
+ let orig_head = self.after_head;
+
+ let tail_len = count(orig_tail, drain_tail, source_deque.cap());
+ let head_len = count(drain_head, orig_head, source_deque.cap());
+
+ // Restore the original head value
+ source_deque.head = orig_head;
+
+ match (tail_len, head_len) {
+ (0, 0) => {
+ source_deque.head = 0;
+ source_deque.tail = 0;
+ }
+ (0, _) => {
+ source_deque.tail = drain_head;
+ }
+ (_, 0) => {
+ source_deque.head = drain_tail;
+ }
+ _ => unsafe {
+ if tail_len <= head_len {
+ source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
+ source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
+ } else {
+ source_deque.head = source_deque.wrap_add(drain_tail, head_len);
+ source_deque.wrap_copy(drain_tail, drain_head, head_len);
+ }
+ }
+ }
}
}
#[inline]
fn next(&mut self) -> Option<T> {
- self.inner.pop_front()
+ self.iter.next().map(|elt|
+ unsafe {
+ ptr::read(elt)
+ }
+ )
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
- let len = self.inner.len();
- (len, Some(len))
+ self.iter.size_hint()
}
}
impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
#[inline]
fn next_back(&mut self) -> Option<T> {
- self.inner.pop_back()
+ self.iter.next_back().map(|elt|
+ unsafe {
+ ptr::read(elt)
+ }
+ )
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: fmt::Debug> fmt::Debug for VecDeque<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "["));
-
- for (i, e) in self.iter().enumerate() {
- if i != 0 { try!(write!(f, ", ")); }
- try!(write!(f, "{:?}", *e));
- }
-
- write!(f, "]")
+ f.debug_list().entries(self).finish()
}
}
}
}
+ #[test]
+ fn test_drain() {
+ let mut tester: VecDeque<usize> = VecDeque::with_capacity(7);
+
+ let cap = tester.capacity();
+ for len in 0..cap + 1 {
+ for tail in 0..cap + 1 {
+ for drain_start in 0..len + 1 {
+ for drain_end in drain_start..len + 1 {
+ tester.tail = tail;
+ tester.head = tail;
+ for i in 0..len {
+ tester.push_back(i);
+ }
+
+ // Check that we drain the correct values
+ let drained: VecDeque<_> =
+ tester.drain(drain_start..drain_end).collect();
+ let drained_expected: VecDeque<_> =
+ (drain_start..drain_end).collect();
+ assert_eq!(drained, drained_expected);
+
+ // We shouldn't have changed the capacity or made the
+ // head or tail out of bounds
+ assert_eq!(tester.capacity(), cap);
+ assert!(tester.tail < tester.cap());
+ assert!(tester.head < tester.cap());
+
+ // We should see the correct values in the VecDeque
+ let expected: VecDeque<_> =
+ (0..drain_start).chain(drain_end..len).collect();
+ assert_eq!(expected, tester);
+ }
+ }
+ }
+ }
+ }
+
#[test]
fn test_shrink_to_fit() {
// This test checks that every single combination of head and tail position,
assert_eq!(a[&3], "three");
}
+#[test]
+fn test_zst() {
+ let mut m = BTreeMap::new();
+ assert_eq!(m.len(), 0);
+
+ assert_eq!(m.insert((), ()), None);
+ assert_eq!(m.len(), 1);
+
+ assert_eq!(m.insert((), ()), Some(()));
+ assert_eq!(m.len(), 1);
+ assert_eq!(m.iter().count(), 1);
+
+ m.clear();
+ assert_eq!(m.len(), 0);
+
+ for _ in 0..100 {
+ m.insert((), ());
+ }
+
+ assert_eq!(m.len(), 1);
+ assert_eq!(m.iter().count(), 1);
+}
+
+// This test's only purpose is to ensure that zero-sized keys with nonsensical orderings
+// do not cause segfaults when used with zero-sized values. All other map behavior is
+// undefined.
+#[test]
+fn test_bad_zst() {
+ use std::cmp::Ordering;
+
+ struct Bad;
+
+ impl PartialEq for Bad {
+ fn eq(&self, _: &Self) -> bool { false }
+ }
+
+ impl Eq for Bad {}
+
+ impl PartialOrd for Bad {
+ fn partial_cmp(&self, _: &Self) -> Option<Ordering> { Some(Ordering::Less) }
+ }
+
+ impl Ord for Bad {
+ fn cmp(&self, _: &Self) -> Ordering { Ordering::Less }
+ }
+
+ let mut m = BTreeMap::new();
+
+ for _ in 0..100 {
+ m.insert(Bad, Bad);
+ }
+}
+
mod bench {
use std::collections::BTreeMap;
use std::__rand::{Rng, thread_rng};
let y = y;
let mut z = x.iter().zip(&y);
- // FIXME: #5801: this needs a type hint to compile...
- let result: Option<(&usize, & &'static str)> = z.next();
- assert_eq!(result.unwrap(), (&5, &("bar")));
-
- let result: Option<(&usize, & &'static str)> = z.next();
- assert_eq!(result.unwrap(), (&11, &("foo")));
-
- let result: Option<(&usize, & &'static str)> = z.next();
- assert!(result.is_none());
+ assert_eq!(z.next().unwrap(), (&5, &("bar")));
+ assert_eq!(z.next().unwrap(), (&11, &("foo")));
+ assert!(z.next().is_none());
}
#[test]
// except according to those terms.
#![feature(ascii)]
-#![feature(append)]
#![feature(binary_heap_extras)]
#![feature(box_syntax)]
#![feature(btree_range)]
#![feature(set_recovery)]
#![feature(slice_bytes)]
#![feature(slice_splits)]
-#![feature(split_off)]
#![feature(step_by)]
#![feature(str_char)]
#![feature(str_escape)]
#![feature(str_match_indices)]
-#![feature(str_split_at)]
#![feature(str_utf16)]
-#![feature(box_str)]
#![feature(test)]
#![feature(unboxed_closures)]
#![feature(unicode)]
-#![feature(vec_deque_retain)]
#![feature(vec_push_all)]
#[macro_use] extern crate log;
#[test]
fn test_collect() {
- let empty = String::from("");
+ let empty = "";
let s: String = empty.chars().collect();
assert_eq!(empty, s);
- let data = String::from("ประเทศไทย中");
+ let data = "ประเทศไทย中";
let s: String = data.chars().collect();
assert_eq!(data, s);
}
assert_eq!(data[43..86].find("iệt"), Some(77 - 43));
assert_eq!(data[43..86].find("Nam"), Some(83 - 43));
- // find every substring -- assert that it finds it, or an earlier occurence.
+ // find every substring -- assert that it finds it, or an earlier occurrence.
let string = "Việt Namacbaabcaabaaba";
for (i, ci) in string.char_indices() {
let ip = i + ci.len_utf8();
rs
}
let letters = a_million_letter_a();
- assert!(half_a_million_letter_a() ==
- unsafe {String::from(letters.slice_unchecked(
- 0,
- 500000))});
+ assert_eq!(half_a_million_letter_a(),
+ unsafe { letters.slice_unchecked(0, 500000)});
}
#[test]
#[test]
fn test_replace() {
let a = "a";
- assert_eq!("".replace(a, "b"), String::from(""));
- assert_eq!("a".replace(a, "b"), String::from("b"));
- assert_eq!("ab".replace(a, "b"), String::from("bb"));
+ assert_eq!("".replace(a, "b"), "");
+ assert_eq!("a".replace(a, "b"), "b");
+ assert_eq!("ab".replace(a, "b"), "bb");
let test = "test";
- assert!(" test test ".replace(test, "toast") ==
- String::from(" toast toast "));
- assert_eq!(" test test ".replace(test, ""), String::from(" "));
+ assert_eq!(" test test ".replace(test, "toast"), " toast toast ");
+ assert_eq!(" test test ".replace(test, ""), " ");
}
#[test]
rs
}
let letters = a_million_letter_x();
- assert!(half_a_million_letter_x() ==
- String::from(&letters[0..3 * 500000]));
+ assert_eq!(half_a_million_letter_x(), &letters[0..3 * 500000]);
}
#[test]
#[test]
fn test_escape_unicode() {
- assert_eq!("abc".escape_unicode(),
- String::from("\\u{61}\\u{62}\\u{63}"));
- assert_eq!("a c".escape_unicode(),
- String::from("\\u{61}\\u{20}\\u{63}"));
- assert_eq!("\r\n\t".escape_unicode(),
- String::from("\\u{d}\\u{a}\\u{9}"));
- assert_eq!("'\"\\".escape_unicode(),
- String::from("\\u{27}\\u{22}\\u{5c}"));
- assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(),
- String::from("\\u{0}\\u{1}\\u{fe}\\u{ff}"));
- assert_eq!("\u{100}\u{ffff}".escape_unicode(),
- String::from("\\u{100}\\u{ffff}"));
- assert_eq!("\u{10000}\u{10ffff}".escape_unicode(),
- String::from("\\u{10000}\\u{10ffff}"));
- assert_eq!("ab\u{fb00}".escape_unicode(),
- String::from("\\u{61}\\u{62}\\u{fb00}"));
- assert_eq!("\u{1d4ea}\r".escape_unicode(),
- String::from("\\u{1d4ea}\\u{d}"));
+ assert_eq!("abc".escape_unicode(), "\\u{61}\\u{62}\\u{63}");
+ assert_eq!("a c".escape_unicode(), "\\u{61}\\u{20}\\u{63}");
+ assert_eq!("\r\n\t".escape_unicode(), "\\u{d}\\u{a}\\u{9}");
+ assert_eq!("'\"\\".escape_unicode(), "\\u{27}\\u{22}\\u{5c}");
+ assert_eq!("\x00\x01\u{fe}\u{ff}".escape_unicode(), "\\u{0}\\u{1}\\u{fe}\\u{ff}");
+ assert_eq!("\u{100}\u{ffff}".escape_unicode(), "\\u{100}\\u{ffff}");
+ assert_eq!("\u{10000}\u{10ffff}".escape_unicode(), "\\u{10000}\\u{10ffff}");
+ assert_eq!("ab\u{fb00}".escape_unicode(), "\\u{61}\\u{62}\\u{fb00}");
+ assert_eq!("\u{1d4ea}\r".escape_unicode(), "\\u{1d4ea}\\u{d}");
}
#[test]
fn test_escape_default() {
- assert_eq!("abc".escape_default(), String::from("abc"));
- assert_eq!("a c".escape_default(), String::from("a c"));
- assert_eq!("\r\n\t".escape_default(), String::from("\\r\\n\\t"));
- assert_eq!("'\"\\".escape_default(), String::from("\\'\\\"\\\\"));
- assert_eq!("\u{100}\u{ffff}".escape_default(),
- String::from("\\u{100}\\u{ffff}"));
- assert_eq!("\u{10000}\u{10ffff}".escape_default(),
- String::from("\\u{10000}\\u{10ffff}"));
- assert_eq!("ab\u{fb00}".escape_default(),
- String::from("ab\\u{fb00}"));
- assert_eq!("\u{1d4ea}\r".escape_default(),
- String::from("\\u{1d4ea}\\r"));
+ assert_eq!("abc".escape_default(), "abc");
+ assert_eq!("a c".escape_default(), "a c");
+ assert_eq!("\r\n\t".escape_default(), "\\r\\n\\t");
+ assert_eq!("'\"\\".escape_default(), "\\'\\\"\\\\");
+ assert_eq!("\u{100}\u{ffff}".escape_default(), "\\u{100}\\u{ffff}");
+ assert_eq!("\u{10000}\u{10ffff}".escape_default(), "\\u{10000}\\u{10ffff}");
+ assert_eq!("ab\u{fb00}".escape_default(), "ab\\u{fb00}");
+ assert_eq!("\u{1d4ea}\r".escape_default(), "\\u{1d4ea}\\r");
}
#[test]
fn test_total_ord() {
- "1234".cmp("123") == Greater;
- "123".cmp("1234") == Less;
- "1234".cmp("1234") == Equal;
- "12345555".cmp("123456") == Less;
- "22".cmp("1234") == Greater;
+ assert_eq!("1234".cmp("123"), Greater);
+ assert_eq!("123".cmp("1234"), Less);
+ assert_eq!("1234".cmp("1234"), Equal);
+ assert_eq!("12345555".cmp("123456"), Less);
+ assert_eq!("22".cmp("1234"), Greater);
}
#[test]
v.iter().map(|x| x.len()).sum()
}
- let s = String::from("01234");
+ let s = "01234";
assert_eq!(5, sum_len(&["012", "", "34"]));
- assert_eq!(5, sum_len(&[&String::from("01"),
- &String::from("2"),
- &String::from("34"),
- &String::from("")]));
- assert_eq!(5, sum_len(&[&s]));
+ assert_eq!(5, sum_len(&["01", "2", "34", ""]));
+ assert_eq!(5, sum_len(&[s]));
}
#[test]
fn test_empty_match_indices() {
let data = "aä中!";
let vec: Vec<_> = data.match_indices("").collect();
- assert_eq!(vec, [(0, 0), (1, 1), (3, 3), (6, 6), (7, 7)]);
+ assert_eq!(vec, [(0, ""), (1, ""), (3, ""), (6, ""), (7, "")]);
}
#[test]
generate_iterator_test! {
double_ended_match_indices {
- ("a1b2c3", char::is_numeric) -> [(1, 2), (3, 4), (5, 6)];
+ ("a1b2c3", char::is_numeric) -> [(1, "1"), (3, "2"), (5, "3")];
}
with str::match_indices, str::rmatch_indices;
}
#[test]
fn remove() {
- let mut s = "ศไทย中华Việt Nam; foobar".to_string();;
+ let mut s = "ศไทย中华Việt Nam; foobar".to_string();
assert_eq!(s.remove(0), 'ศ');
assert_eq!(s.len(), 33);
assert_eq!(s, "ไทย中华Việt Nam; foobar");
let mut d: VecDeque<i32> = VecDeque::new();
{
- let mut iter = d.drain();
+ let mut iter = d.drain(..);
assert_eq!(iter.size_hint(), (0, Some(0)));
assert_eq!(iter.next(), None);
d.push_back(i);
}
- assert_eq!(d.drain().collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
+ assert_eq!(d.drain(..).collect::<Vec<_>>(), [0, 1, 2, 3, 4]);
assert!(d.is_empty());
}
d.push_front(i);
}
- assert_eq!(d.drain().collect::<Vec<_>>(), [8,7,6,0,1,2,3,4]);
+ assert_eq!(d.drain(..).collect::<Vec<_>>(), [8,7,6,0,1,2,3,4]);
assert!(d.is_empty());
}
}
{
- let mut it = d.drain();
+ let mut it = d.drain(..);
assert_eq!(it.size_hint(), (8, Some(8)));
assert_eq!(it.next(), Some(8));
assert_eq!(it.size_hint(), (7, Some(7)));
///
/// This trait can be used to implement other traits on fixed-size arrays
/// without causing much metadata bloat.
-pub trait FixedSizeArray<T> {
+///
+/// The trait is marked unsafe in order to restrict implementors to fixed-size
+/// arrays. User of this trait can assume that implementors have the exact
+/// layout in memory of a fixed size array (for example, for unsafe
+/// initialization).
+///
+/// Note that the traits AsRef and AsMut provide similar methods for types that
+/// may not be fixed-size arrays. Implementors should prefer those traits
+/// instead.
+pub unsafe trait FixedSizeArray<T> {
/// Converts the array to immutable slice
fn as_slice(&self) -> &[T];
/// Converts the array to mutable slice
fn as_mut_slice(&mut self) -> &mut [T];
}
-impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
+unsafe impl<T, A: Unsize<[T]>> FixedSizeArray<T> for A {
#[inline]
fn as_slice(&self) -> &[T] {
self
/// Returns a reference to the underlying `UnsafeCell`.
///
- /// # Unsafety
+ /// # Safety
///
/// This function is `unsafe` because `UnsafeCell`'s field is public.
///
}
}
- /// Make a new `Ref` for a optional component of the borrowed data, e.g. an
+ /// Make a new `Ref` for an optional component of the borrowed data, e.g. an
/// enum variant.
///
/// The `RefCell` is already immutably borrowed, so this cannot fail.
}
}
- /// Make a new `RefMut` for a optional component of the borrowed data, e.g.
+ /// Make a new `RefMut` for an optional component of the borrowed data, e.g.
/// an enum variant.
///
/// The `RefCell` is already mutably borrowed, so this cannot fail.
///
/// unsafe impl<T> Sync for NotThreadSafe<T> {}
/// ```
-///
-/// **NOTE:** `UnsafeCell<T>`'s fields are public to allow static initializers. It is not
-/// recommended to access its fields directly, `get` should be used instead.
#[lang = "unsafe_cell"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct UnsafeCell<T: ?Sized> {
/// Constructs a new instance of `UnsafeCell` which will wrap the specified
/// value.
///
- /// All access to the inner value through methods is `unsafe`, and it is highly discouraged to
- /// access the fields directly.
+ /// All access to the inner value through methods is `unsafe`.
///
/// # Examples
///
/// Unwraps the value.
///
- /// # Unsafety
+ /// # Safety
///
/// This function is unsafe because this thread or another thread may currently be
/// inspecting the inner value.
/// Converts a `u32` to an `char`, not checking whether it is a valid unicode
/// codepoint.
#[inline]
-#[unstable(feature = "char_from_unchecked", reason = "recently added API",
- issue = "27781")]
+#[stable(feature = "char_from_unchecked", since = "1.5.0")]
pub unsafe fn from_u32_unchecked(i: u32) -> char {
transmute(i)
}
'\t' => EscapeDefaultState::Backslash('t'),
'\r' => EscapeDefaultState::Backslash('r'),
'\n' => EscapeDefaultState::Backslash('n'),
- '\\' => EscapeDefaultState::Backslash('\\'),
- '\'' => EscapeDefaultState::Backslash('\''),
- '"' => EscapeDefaultState::Backslash('"'),
+ '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self),
'\x20' ... '\x7e' => EscapeDefaultState::Char(self),
_ => EscapeDefaultState::Unicode(self.escape_unicode())
};
EscapeUnicodeState::Done => None,
}
}
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ let mut n = 0;
+ while (self.c as usize) >> (4 * (n + 1)) != 0 {
+ n += 1;
+ }
+ let n = match self.state {
+ EscapeUnicodeState::Backslash => n + 5,
+ EscapeUnicodeState::Type => n + 4,
+ EscapeUnicodeState::LeftBrace => n + 3,
+ EscapeUnicodeState::Value(offset) => offset + 2,
+ EscapeUnicodeState::RightBrace => 1,
+ EscapeUnicodeState::Done => 0,
+ };
+ (n, Some(n))
+ }
}
/// An iterator over the characters that represent a `char`, escaped
Some(c)
}
EscapeDefaultState::Done => None,
- EscapeDefaultState::Unicode(ref mut iter) => iter.next()
+ EscapeDefaultState::Unicode(ref mut iter) => iter.next(),
+ }
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ match self.state {
+ EscapeDefaultState::Char(_) => (1, Some(1)),
+ EscapeDefaultState::Backslash(_) => (2, Some(2)),
+ EscapeDefaultState::Unicode(ref iter) => iter.size_hint(),
+ EscapeDefaultState::Done => (0, Some(0)),
}
}
}
///
/// The comparison must satisfy, for all `a`, `b` and `c`:
///
-/// - antisymmetry: if `a < b` then `!(a > b)` and vice versa; and
+/// - antisymmetry: if `a < b` then `!(a > b)`, as well as `a > b` implying `!(a < b)`; and
/// - transitivity: `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
///
/// Note that these requirements mean that the trait itself must be implemented symmetrically and
}
}
- partial_ord_impl! { char usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+ partial_ord_impl! { f32 f64 }
macro_rules! ord_impl {
($($t:ty)*) => ($(
+ #[stable(feature = "rust1", since = "1.0.0")]
+ impl PartialOrd for $t {
+ #[inline]
+ fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+ #[inline]
+ fn lt(&self, other: &$t) -> bool { (*self) < (*other) }
+ #[inline]
+ fn le(&self, other: &$t) -> bool { (*self) <= (*other) }
+ #[inline]
+ fn ge(&self, other: &$t) -> bool { (*self) >= (*other) }
+ #[inline]
+ fn gt(&self, other: &$t) -> bool { (*self) > (*other) }
+ }
+
#[stable(feature = "rust1", since = "1.0.0")]
impl Ord for $t {
#[inline]
fn cmp(&self, other: &$t) -> Ordering {
- if *self < *other { Less }
- else if *self > *other { Greater }
- else { Equal }
+ if *self == *other { Equal }
+ else if *self < *other { Less }
+ else { Greater }
}
}
)*)
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, A: $Bound, B> PartialEq<$Rhs> for $Lhs where A: PartialEq<B> {
#[inline]
- fn eq(&self, other: &$Rhs) -> bool { &self[..] == &other[..] }
+ fn eq(&self, other: &$Rhs) -> bool { self[..] == other[..] }
#[inline]
- fn ne(&self, other: &$Rhs) -> bool { &self[..] != &other[..] }
+ fn ne(&self, other: &$Rhs) -> bool { self[..] != other[..] }
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, A: $Bound, B> PartialEq<$Lhs> for $Rhs where B: PartialEq<A> {
#[inline]
- fn eq(&self, other: &$Lhs) -> bool { &self[..] == &other[..] }
+ fn eq(&self, other: &$Lhs) -> bool { self[..] == other[..] }
#[inline]
- fn ne(&self, other: &$Lhs) -> bool { &self[..] != &other[..] }
+ fn ne(&self, other: &$Lhs) -> bool { self[..] != other[..] }
}
}
}
/// assert_eq!(string, other_string);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub trait From<T> {
+pub trait From<T>: Sized {
/// Performs the conversion.
#[stable(feature = "rust1", since = "1.0.0")]
fn from(T) -> Self;
#![stable(feature = "rust1", since = "1.0.0")]
+use marker::Sized;
+
/// A trait for giving a type a useful default value.
///
/// A struct can derive default implementations of `Default` for basic types using
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
-pub trait Default {
+pub trait Default: Sized {
/// Returns the "default value" for a type.
///
/// Default values are often some kind of initial value, identity value, or anything else that
has_fields: bool,
}
-pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str)
+pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>,
+ name: &str)
-> DebugStruct<'a, 'b> {
let result = fmt.write_str(name);
DebugStruct {
if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt);
- fmt::write(&mut writer, format_args!("{}\n{}: {:#?}", prefix, name, value))
+ fmt::write(&mut writer,
+ format_args!("{}\n{}: {:#?}", prefix, name, value))
} else {
write!(self.fmt, "{} {}: {:?}", prefix, name, value)
}
self.result = self.result.and_then(|_| {
if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt);
- let prefix = if self.has_fields { "," } else { "" };
+ let prefix = if self.has_fields {
+ ","
+ } else {
+ ""
+ };
fmt::write(&mut writer, format_args!("{}\n{:#?}", prefix, entry))
} else {
- let prefix = if self.has_fields { ", " } else { "" };
+ let prefix = if self.has_fields {
+ ", "
+ } else {
+ ""
+ };
write!(self.fmt, "{}{:?}", prefix, entry)
}
});
}
pub fn finish(&mut self) {
- let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" };
+ let prefix = if self.is_pretty() && self.has_fields {
+ "\n"
+ } else {
+ ""
+ };
self.result = self.result.and_then(|_| self.fmt.write_str(prefix));
}
fmt: fmt,
result: result,
has_fields: false,
- }
+ },
}
}
/// Adds the contents of an iterator of entries to the set output.
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugSet<'a, 'b>
- where D: fmt::Debug, I: IntoIterator<Item=D> {
+ where D: fmt::Debug,
+ I: IntoIterator<Item = D>
+ {
for entry in entries {
self.entry(&entry);
}
fmt: fmt,
result: result,
has_fields: false,
- }
+ },
}
}
/// Adds the contents of an iterator of entries to the list output.
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entries<D, I>(&mut self, entries: I) -> &mut DebugList<'a, 'b>
- where D: fmt::Debug, I: IntoIterator<Item=D> {
+ where D: fmt::Debug,
+ I: IntoIterator<Item = D>
+ {
for entry in entries {
self.entry(&entry);
}
self.result = self.result.and_then(|_| {
if self.is_pretty() {
let mut writer = PadAdapter::new(self.fmt);
- let prefix = if self.has_fields { "," } else { "" };
- fmt::write(&mut writer, format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
+ let prefix = if self.has_fields {
+ ","
+ } else {
+ ""
+ };
+ fmt::write(&mut writer,
+ format_args!("{}\n{:#?}: {:#?}", prefix, key, value))
} else {
- let prefix = if self.has_fields { ", " } else { "" };
+ let prefix = if self.has_fields {
+ ", "
+ } else {
+ ""
+ };
write!(self.fmt, "{}{:?}: {:?}", prefix, key, value)
}
});
/// Adds the contents of an iterator of entries to the map output.
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn entries<K, V, I>(&mut self, entries: I) -> &mut DebugMap<'a, 'b>
- where K: fmt::Debug, V: fmt::Debug, I: IntoIterator<Item=(K, V)> {
+ where K: fmt::Debug,
+ V: fmt::Debug,
+ I: IntoIterator<Item = (K, V)>
+ {
for (k, v) in entries {
self.entry(&k, &v);
}
/// Finishes output and returns any error encountered.
#[stable(feature = "debug_builders", since = "1.2.0")]
pub fn finish(&mut self) -> fmt::Result {
- let prefix = if self.is_pretty() && self.has_fields { "\n" } else { "" };
+ let prefix = if self.is_pretty() && self.has_fields {
+ "\n"
+ } else {
+ ""
+ };
self.result.and_then(|_| write!(self.fmt, "{}}}", prefix))
}
self.write_str(unsafe { str::from_utf8_unchecked(&utf_8[..bytes_written]) })
}
- /// Glue for usage of the `write!` macro with implementers of this trait.
+ /// Glue for usage of the `write!` macro with implementors of this trait.
///
/// This method should generally not be invoked manually, but rather through
/// the `write!` macro itself.
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
/// Format trait for the `x` character.
///
-/// The `LowerHex` trait should format its output as a number in hexidecimal, with `a` through `f`
+/// The `LowerHex` trait should format its output as a number in hexadecimal, with `a` through `f`
/// in lower case.
///
/// The alternate flag, `#`, adds a `0x` in front of the output.
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
/// Format trait for the `X` character.
///
-/// The `UpperHex` trait should format its output as a number in hexidecimal, with `A` through `F`
+/// The `UpperHex` trait should format its output as a number in hexadecimal, with `A` through `F`
/// in upper case.
///
/// The alternate flag, `#`, adds a `0x` in front of the output.
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
/// Format trait for the `p` character.
///
/// The `Pointer` trait should format its output as a memory location. This is commonly presented
-/// as hexidecimal.
+/// as hexadecimal.
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
///
/// For more information on formatters, see [the module-level documentation][module].
///
-/// [module]: ../index.html
+/// [module]: ../../std/fmt/index.html
///
/// # Examples
///
let mut sign = None;
if !is_positive {
sign = Some('-'); width += 1;
- } else if self.flags & (1 << (FlagV1::SignPlus as u32)) != 0 {
+ } else if self.sign_plus() {
sign = Some('+'); width += 1;
}
let mut prefixed = false;
- if self.flags & (1 << (FlagV1::Alternate as u32)) != 0 {
+ if self.alternate() {
prefixed = true; width += prefix.char_len();
}
}
// The sign and prefix goes before the padding if the fill character
// is zero
- Some(min) if self.flags & (1 << (FlagV1::SignAwareZeroPad as u32)) != 0 => {
+ Some(min) if self.sign_aware_zero_pad() => {
self.fill = '0';
try!(write_prefix(self));
self.with_padding(min - width, Alignment::Right, |f| {
let mut formatted = formatted.clone();
let mut align = self.align;
let old_fill = self.fill;
- if self.flags & (1 << (FlagV1::SignAwareZeroPad as u32)) != 0 {
+ if self.sign_aware_zero_pad() {
// a sign always goes first
let sign = unsafe { str::from_utf8_unchecked(formatted.sign) };
try!(self.buf.write_str(sign));
pub fn flags(&self) -> u32 { self.flags }
/// Character used as 'fill' whenever there is alignment
- #[unstable(feature = "fmt_flags", reason = "method was just created",
- issue = "27726")]
+ #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn fill(&self) -> char { self.fill }
/// Flag indicating what form of alignment was requested
- #[unstable(feature = "fmt_flags", reason = "method was just created",
+ #[unstable(feature = "fmt_flags_align", reason = "method was just created",
issue = "27726")]
pub fn align(&self) -> Alignment { self.align }
/// Optionally specified integer width that the output should be
- #[unstable(feature = "fmt_flags", reason = "method was just created",
- issue = "27726")]
+ #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn width(&self) -> Option<usize> { self.width }
/// Optionally specified precision for numeric types
- #[unstable(feature = "fmt_flags", reason = "method was just created",
- issue = "27726")]
+ #[stable(feature = "fmt_flags", since = "1.5.0")]
pub fn precision(&self) -> Option<usize> { self.precision }
+ /// Determines if the `+` flag was specified.
+ #[stable(feature = "fmt_flags", since = "1.5.0")]
+ pub fn sign_plus(&self) -> bool { self.flags & (1 << FlagV1::SignPlus as u32) != 0 }
+
+ /// Determines if the `-` flag was specified.
+ #[stable(feature = "fmt_flags", since = "1.5.0")]
+ pub fn sign_minus(&self) -> bool { self.flags & (1 << FlagV1::SignMinus as u32) != 0 }
+
+ /// Determines if the `#` flag was specified.
+ #[stable(feature = "fmt_flags", since = "1.5.0")]
+ pub fn alternate(&self) -> bool { self.flags & (1 << FlagV1::Alternate as u32) != 0 }
+
+ /// Determines if the `0` flag was specified.
+ #[stable(feature = "fmt_flags", since = "1.5.0")]
+ pub fn sign_aware_zero_pad(&self) -> bool {
+ self.flags & (1 << FlagV1::SignAwareZeroPad as u32) != 0
+ }
+
/// Creates a `DebugStruct` builder designed to assist with creation of
/// `fmt::Debug` implementations for structs.
///
#[stable(feature = "rust1", since = "1.0.0")]
impl Debug for str {
fn fmt(&self, f: &mut Formatter) -> Result {
- try!(write!(f, "\""));
- for c in self.chars().flat_map(|c| c.escape_default()) {
- try!(f.write_char(c))
+ try!(f.write_char('"'));
+ let mut from = 0;
+ for (i, c) in self.char_indices() {
+ let esc = c.escape_default();
+ // If char needs escaping, flush backlog so far and write, else skip
+ if esc.size_hint() != (1, Some(1)) {
+ try!(f.write_str(&self[from..i]));
+ for c in esc {
+ try!(f.write_char(c));
+ }
+ from = i + c.len_utf8();
+ }
}
- write!(f, "\"")
+ try!(f.write_str(&self[from..]));
+ f.write_char('"')
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Debug for char {
fn fmt(&self, f: &mut Formatter) -> Result {
- use char::CharExt;
- try!(write!(f, "'"));
+ try!(f.write_char('\''));
for c in self.escape_default() {
try!(f.write_char(c))
}
- write!(f, "'")
+ f.write_char('\'')
}
}
// it denotes whether to prefix with 0x. We use it to work out whether
// or not to zero extend, and then unconditionally set it to get the
// prefix.
- if f.flags & 1 << (FlagV1::Alternate as u32) > 0 {
+ if f.alternate() {
f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
if let None = f.width {
fn float_to_decimal_common<T>(fmt: &mut Formatter, num: &T, negative_zero: bool) -> Result
where T: flt2dec::DecodableFloat
{
- let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0;
+ let force_sign = fmt.sign_plus();
let sign = match (force_sign, negative_zero) {
(false, false) => flt2dec::Sign::Minus,
(false, true) => flt2dec::Sign::MinusRaw,
fn float_to_exponential_common<T>(fmt: &mut Formatter, num: &T, upper: bool) -> Result
where T: flt2dec::DecodableFloat
{
- let force_sign = fmt.flags & (1 << (FlagV1::SignPlus as u32)) != 0;
+ let force_sign = fmt.sign_plus();
let sign = match force_sign {
false => flt2dec::Sign::Minus,
true => flt2dec::Sign::MinusPlus,
fn base(&self) -> u8;
/// A radix-specific prefix string.
- fn prefix(&self) -> &'static str { "" }
+ fn prefix(&self) -> &'static str {
+ ""
+ }
/// Converts an integer to corresponding radix digit.
fn digit(&self, x: u8) -> u8;
x = x / base; // Deaccumulate the number.
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
curr -= 1;
- if x == zero { break }; // No more digits left to accumulate.
+ if x == zero {
+ // No more digits left to accumulate.
+ break
+ };
}
} else {
// Do the same as above, but accounting for two's complement.
x = x / base; // Deaccumulate the number.
*byte = self.digit(n.to_u8()); // Store the digit in the buffer.
curr -= 1;
- if x == zero { break }; // No more digits left to accumulate.
+ if x == zero {
+ // No more digits left to accumulate.
+ break
+ };
}
}
let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
impl Radix {
fn new(base: u8) -> Radix {
- assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base);
+ assert!(2 <= base && base <= 36,
+ "the base must be in the range of 2..36: {}",
+ base);
Radix { base: base }
}
}
impl GenericRadix for Radix {
- fn base(&self) -> u8 { self.base }
+ fn base(&self) -> u8 {
+ self.base
+ }
fn digit(&self, x: u8) -> u8 {
match x {
x @ 0 ... 9 => b'0' + x,
#[derive(Copy, Clone)]
pub enum Position {
Next,
- At(usize)
+ At(usize),
}
/// Feeds a slice of this type into the state provided.
#[stable(feature = "hash_slice", since = "1.3.0")]
- fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) where Self: Sized {
+ fn hash_slice<H: Hasher>(data: &[Self], state: &mut H)
+ where Self: Sized
+ {
for piece in data {
piece.hash(state);
}
/// Write a single `u8` into this hasher
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
- fn write_u8(&mut self, i: u8) { self.write(&[i]) }
+ fn write_u8(&mut self, i: u8) {
+ self.write(&[i])
+ }
/// Write a single `u16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
#[stable(feature = "hasher_write", since = "1.3.0")]
fn write_usize(&mut self, i: usize) {
let bytes = unsafe {
- ::slice::from_raw_parts(&i as *const usize as *const u8,
- mem::size_of::<usize>())
+ ::slice::from_raw_parts(&i as *const usize as *const u8, mem::size_of::<usize>())
};
self.write(bytes);
}
/// Write a single `i8` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
- fn write_i8(&mut self, i: i8) { self.write_u8(i as u8) }
+ fn write_i8(&mut self, i: i8) {
+ self.write_u8(i as u8)
+ }
/// Write a single `i16` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
- fn write_i16(&mut self, i: i16) { self.write_u16(i as u16) }
+ fn write_i16(&mut self, i: i16) {
+ self.write_u16(i as u16)
+ }
/// Write a single `i32` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
- fn write_i32(&mut self, i: i32) { self.write_u32(i as u32) }
+ fn write_i32(&mut self, i: i32) {
+ self.write_u32(i as u32)
+ }
/// Write a single `i64` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
- fn write_i64(&mut self, i: i64) { self.write_u64(i as u64) }
+ fn write_i64(&mut self, i: i64) {
+ self.write_u64(i as u64)
+ }
/// Write a single `isize` into this hasher.
#[inline]
#[stable(feature = "hasher_write", since = "1.3.0")]
- fn write_isize(&mut self, i: isize) { self.write_usize(i as usize) }
+ fn write_isize(&mut self, i: isize) {
+ self.write_usize(i as usize)
+ }
}
//////////////////////////////////////////////////////////////////////////////
// and simd implementations of SipHash will use vectors
// of v02 and v13. By placing them in this order in the struct,
// the compiler can pick up on just a few simd optimizations by itself.
- v0: u64, // hash state
+ v0: u64, // hash state
v2: u64,
v1: u64,
v3: u64,
tail: u64, // unprocessed bytes le
- ntail: usize, // how many bytes in tail are valid
+ ntail: usize, // how many bytes in tail are valid
}
// sadly, these macro definitions can't appear later,
unsafe fn load_u64_le(buf: &[u8], i: usize) -> u64 {
debug_assert!(i + 8 <= buf.len());
let mut data = 0u64;
- ptr::copy_nonoverlapping(buf.get_unchecked(i),
- &mut data as *mut _ as *mut u8, 8);
+ ptr::copy_nonoverlapping(buf.get_unchecked(i), &mut data as *mut _ as *mut u8, 8);
data.to_le()
}
if self.ntail != 0 {
needed = 8 - self.ntail;
if length < needed {
- self.tail |= u8to64_le!(msg, 0, length) << 8*self.ntail;
+ self.tail |= u8to64_le!(msg, 0, length) << 8 * self.ntail;
self.ntail += length;
return
}
- let m = self.tail | u8to64_le!(msg, 0, needed) << 8*self.ntail;
+ let m = self.tail | u8to64_le!(msg, 0, needed) << 8 * self.ntail;
self.v3 ^= m;
compress!(self.v0, self.v1, self.v2, self.v3);
/// # Safety
///
/// Beyond requiring that the program must be allowed to access both regions
- /// of memory, it is Undefined Behaviour for source and destination to
+ /// of memory, it is Undefined Behavior for source and destination to
/// overlap. Care must also be taken with the ownership of `src` and
/// `dst`. This method semantically moves the values of `src` into `dst`.
/// However it does not drop the contents of `dst`, or prevent the contents
/// a size of `count` * `size_of::<T>()` and an alignment of
/// `min_align_of::<T>()`
///
- /// The volatile parameter parameter is set to `true`, so it will not be optimized out.
+ /// The volatile parameter is set to `true`, so it will not be optimized out.
pub fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
count: usize);
/// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with
/// a size of `count` * `size_of::<T>()` and an alignment of
/// `min_align_of::<T>()`
///
- /// The volatile parameter parameter is set to `true`, so it will not be optimized out.
+ /// The volatile parameter is set to `true`, so it will not be optimized out.
pub fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize);
/// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a
/// size of `count` * `size_of::<T>()` and an alignment of
/// `min_align_of::<T>()`.
///
- /// The volatile parameter parameter is set to `true`, so it will not be optimized out.
+ /// The volatile parameter is set to `true`, so it will not be optimized out.
pub fn volatile_set_memory<T>(dst: *mut T, val: u8, count: usize);
/// Perform a volatile load from the `src` pointer.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Composable external iterators
+//! Composable external iteration
//!
-//! # The `Iterator` trait
+//! If you've found yourself with a collection of some kind, and needed to
+//! perform an operation on the elements of said collection, you'll quickly run
+//! into 'iterators'. Iterators are heavily used in idiomatic Rust code, so
+//! it's worth becoming familiar with them.
//!
-//! This module defines Rust's core iteration trait. The `Iterator` trait has
-//! one unimplemented method, `next`. All other methods are derived through
-//! default methods to perform operations such as `zip`, `chain`, `enumerate`,
-//! and `fold`.
+//! Before explaining more, let's talk about how this module is structured:
//!
-//! The goal of this module is to unify iteration across all containers in Rust.
-//! An iterator can be considered as a state machine which is used to track
-//! which element will be yielded next.
+//! # Organization
//!
-//! There are various extensions also defined in this module to assist with
-//! various types of iteration, such as the `DoubleEndedIterator` for iterating
-//! in reverse, the `FromIterator` trait for creating a container from an
-//! iterator, and much more.
+//! This module is largely organized by type:
//!
-//! # Rust's `for` loop
+//! * [Traits] are the core portion: these traits define what kind of iterators
+//! exist and what you can do with them. The methods of these traits are worth
+//! putting some extra study time into.
+//! * [Functions] provide some helpful ways to create some basic iterators.
+//! * [Structs] are often the return types of the various methods on this
+//! module's traits. You'll usually want to look at the method that creates
+//! the `struct`, rather than the `struct` itself. For more detail about why,
+//! see '[Implementing Iterator](#implementing-iterator)'.
//!
-//! The special syntax used by rust's `for` loop is based around the
-//! `IntoIterator` trait defined in this module. `for` loops can be viewed as a
-//! syntactical expansion into a `loop`, for example, the `for` loop in this
-//! example is essentially translated to the `loop` below.
+//! [Traits]: #traits
+//! [Functions]: #functions
+//! [Structs]: #structs
+//!
+//! That's it! Let's dig into iterators.
+//!
+//! # Iterator
+//!
+//! The heart and soul of this module is the [`Iterator`] trait. The core of
+//! [`Iterator`] looks like this:
+//!
+//! ```
+//! trait Iterator {
+//! type Item;
+//! fn next(&mut self) -> Option<Self::Item>;
+//! }
+//! ```
+//!
+//! An iterator has a method, [`next()`], which when called, returns an
+//! [`Option`]`<Item>`. [`next()`] will return `Some(Item)` as long as there
+//! are elements, and once they've all been exhausted, will return `None` to
+//! indicate that iteration is finished. Individual iterators may choose to
+//! resume iteration, and so calling [`next()`] again may or may not eventually
+//! start returning `Some(Item)` again at some point.
+//!
+//! [`Iterator`]'s full definition includes a number of other methods as well,
+//! but they are default methods, built on top of [`next()`], and so you get
+//! them for free.
+//!
+//! Iterators are also composable, and it's common to chain them together to do
+//! more complex forms of processing. See the [Adapters](#adapters) section
+//! below for more details.
+//!
+//! [`Iterator`]: trait.Iterator.html
+//! [`next()`]: trait.Iterator.html#tymethod.next
+//! [`Option`]: ../option/enum.Option.html
+//!
+//! # The three forms of iteration
+//!
+//! There are three common methods which can create iterators from a collection:
+//!
+//! * `iter()`, which iterates over `&T`.
+//! * `iter_mut()`, which iterates over `&mut T`.
+//! * `into_iter()`, which iterates over `T`.
+//!
+//! Various things in the standard library may implement one or more of the
+//! three, where appropriate.
+//!
+//! # Implementing Iterator
+//!
+//! Creating an iterator of your own involves two steps: creating a `struct` to
+//! hold the iterator's state, and then `impl`ementing [`Iterator`] for that
+//! `struct`. This is why there are so many `struct`s in this module: there is
+//! one for each iterator and iterator adapter.
+//!
+//! Let's make an iterator named `Counter` which counts from `1` to `5`:
//!
//! ```
-//! let values = vec![1, 2, 3];
+//! // First, the struct:
+//!
+//! /// An iterator which counts from one to five
+//! struct Counter {
+//! count: usize,
+//! }
+//!
+//! // we want our count to start at one, so let's add a new() method to help.
+//! // This isn't strictly necessary, but is convenient. Note that we start
+//! // `count` at zero, we'll see why in `next()`'s implementation below.
+//! impl Counter {
+//! fn new() -> Counter {
+//! Counter { count: 0 }
+//! }
+//! }
+//!
+//! // Then, we implement `Iterator` for our `Counter`:
+//!
+//! impl Iterator for Counter {
+//! // we will be counting with usize
+//! type Item = usize;
+//!
+//! // next() is the only required method
+//! fn next(&mut self) -> Option<usize> {
+//! // increment our count. This is why we started at zero.
+//! self.count += 1;
+//!
+//! // check to see if we've finished counting or not.
+//! if self.count < 6 {
+//! Some(self.count)
+//! } else {
+//! None
+//! }
+//! }
+//! }
+//!
+//! // And now we can use it!
+//!
+//! let mut counter = Counter::new();
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//!
+//! let x = counter.next().unwrap();
+//! println!("{}", x);
+//! ```
+//!
+//! This will print `1` through `5`, each on their own line.
+//!
+//! Calling `next()` this way gets repetitive. Rust has a construct which can
+//! call `next()` on your iterator, until it reaches `None`. Let's go over that
+//! next.
+//!
+//! # for Loops and IntoIterator
+//!
+//! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic
+//! example of `for`:
+//!
+//! ```
+//! let values = vec![1, 2, 3, 4, 5];
//!
//! for x in values {
//! println!("{}", x);
//! }
+//! ```
//!
-//! // Rough translation of the iteration without a `for` iterator.
-//! # let values = vec![1, 2, 3];
-//! let mut it = values.into_iter();
-//! loop {
-//! match it.next() {
-//! Some(x) => println!("{}", x),
-//! None => break,
-//! }
+//! This will print the numbers one through five, each on their own line. But
+//! you'll notice something here: we never called anything on our vector to
+//! produce an iterator. What gives?
+//!
+//! There's a trait in the standard library for converting something into an
+//! iterator: [`IntoIterator`]. This trait has one method, [`into_iter()`],
+//! which converts the thing implementing [`IntoIterator`] into an iterator.
+//! Let's take a look at that `for` loop again, and what the compiler converts
+//! it into:
+//!
+//! [`IntoIterator`]: trait.IntoIterator.html
+//! [`into_iter()`]: trait.IntoIterator.html#tymethod.into_iter
+//!
+//! ```
+//! let values = vec![1, 2, 3, 4, 5];
+//!
+//! for x in values {
+//! println!("{}", x);
//! }
//! ```
//!
-//! Because `Iterator`s implement `IntoIterator`, this `for` loop syntax can be
-//! applied to any iterator over any type.
+//! Rust de-sugars this into:
+//!
+//! ```
+//! let values = vec![1, 2, 3, 4, 5];
+//! {
+//! let result = match values.into_iter() {
+//! mut iter => loop {
+//! match iter.next() {
+//! Some(x) => { println!("{}", x); },
+//! None => break,
+//! }
+//! },
+//! };
+//! result
+//! }
+//! ```
+//!
+//! First, we call `into_iter()` on the value. Then, we match on the iterator
+//! that returns, calling [`next()`] over and over until we see a `None`. At
+//! that point, we `break` out of the loop, and we're done iterating.
+//!
+//! There's one more subtle bit here: the standard library contains an
+//! interesting implementation of [`IntoIterator`]:
+//!
+//! ```ignore
+//! impl<I: Iterator> IntoIterator for I
+//! ```
+//!
+//! In other words, all [`Iterator`]s implement [`IntoIterator`], by just
+//! returning themselves. This means two things:
+//!
+//! 1. If you're writing an [`Iterator`], you can use it with a `for` loop.
+//! 2. If you're creating a collection, implementing [`IntoIterator`] for it
+//! will allow your collection to be used with the `for` loop.
+//!
+//! # Adapters
+//!
+//! Functions which take an [`Iterator`] and return another [`Iterator`] are
+//! often called 'iterator adapters', as they're a form of the 'adapter
+//! pattern'.
+//!
+//! Common iterator adapters include [`map()`], [`take()`], and [`collect()`].
+//! For more, see their documentation.
+//!
+//! [`map()`]: trait.Iterator.html#method.map
+//! [`take()`]: trait.Iterator.html#method.take
+//! [`collect()`]: trait.Iterator.html#method.collect
+//!
+//! # Laziness
+//!
+//! Iterators (and iterator [adapters](#adapters)) are *lazy*. This means that
+//! just creating an iterator doesn't _do_ a whole lot. Nothing really happens
+//! until you call [`next()`]. This is sometimes a source of confusion when
+//! creating an iterator solely for its side effects. For example, the [`map()`]
+//! method calls a closure on each element it iterates over:
+//!
+//! ```
+//! let v = vec![1, 2, 3, 4, 5];
+//! v.iter().map(|x| println!("{}", x));
+//! ```
+//!
+//! This will not print any values, as we only created an iterator, rather than
+//! using it. The compiler will warn us about this kind of behavior:
+//!
+//! ```text
+//! warning: unused result which must be used: iterator adaptors are lazy and
+//! do nothing unless consumed
+//! ```
+//!
+//! The idiomatic way to write a [`map()`] for its side effects is to use a
+//! `for` loop instead:
+//!
+//! ```
+//! let v = vec![1, 2, 3, 4, 5];
+//!
+//! for x in &v {
+//! println!("{}", x);
+//! }
+//! ```
+//!
+//! [`map()`]: trait.Iterator.html#method.map
+//!
+//! The two most common ways to evaluate an iterator are to use a `for` loop
+//! like this, or using the [`collect()`] adapter to produce a new collection.
+//!
+//! [`collect()`]: trait.Iterator.html#method.collect
+//!
+//! # Infinity
+//!
+//! Iterators do not have to be finite. As an example, an open-ended range is
+//! an infinite iterator:
+//!
+//! ```
+//! let numbers = 0..;
+//! ```
+//!
+//! It is common to use the [`take()`] iterator adapter to turn an infinite
+//! iterator into a finite one:
+//!
+//! ```
+//! let numbers = 0..;
+//! let five_numbers = numbers.take(5);
+//!
+//! for number in five_numbers {
+//! println!("{}", number);
+//! }
+//! ```
+//!
+//! This will print the numbers `0` through `4`, each on their own line.
+//!
+//! [`take()`]: trait.Iterator.html#method.take
#![stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
fn nth(&mut self, mut n: usize) -> Option<Self::Item> where Self: Sized {
- for x in self.by_ref() {
+ for x in self {
if n == 0 { return Some(x) }
n -= 1;
}
fn all<F>(&mut self, mut f: F) -> bool where
Self: Sized, F: FnMut(Self::Item) -> bool
{
- for x in self.by_ref() {
+ for x in self {
if !f(x) {
return false;
}
Self: Sized,
F: FnMut(Self::Item) -> bool
{
- for x in self.by_ref() {
+ for x in self {
if f(x) {
return true;
}
Self: Sized,
P: FnMut(&Self::Item) -> bool,
{
- for x in self.by_ref() {
+ for x in self {
if predicate(&x) { return Some(x) }
}
None
P: FnMut(Self::Item) -> bool,
{
// `enumerate` might overflow.
- for (i, x) in self.by_ref().enumerate() {
+ for (i, x) in self.enumerate() {
if predicate(x) {
return Some(i);
}
/// Creates an iterator that clones the elements it yields.
///
- /// This is useful for converting an Iterator<&T> to an Iterator<T>,
+ /// This is useful for converting an `Iterator<&T>` to an`Iterator<T>`,
/// so it's a more convenient form of `map(|&x| x)`.
///
/// # Examples
/// Lexicographically compares the elements of this `Iterator` with those
/// of another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn cmp<I>(mut self, other: I) -> Ordering where
I: IntoIterator<Item = Self::Item>,
Self::Item: Ord,
/// Lexicographically compares the elements of this `Iterator` with those
/// of another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn partial_cmp<I>(mut self, other: I) -> Option<Ordering> where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
/// Determines if the elements of this `Iterator` are equal to those of
/// another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn eq<I>(mut self, other: I) -> bool where
I: IntoIterator,
Self::Item: PartialEq<I::Item>,
/// Determines if the elements of this `Iterator` are unequal to those of
/// another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn ne<I>(mut self, other: I) -> bool where
I: IntoIterator,
Self::Item: PartialEq<I::Item>,
/// Determines if the elements of this `Iterator` are lexicographically
/// less than those of another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn lt<I>(mut self, other: I) -> bool where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
/// Determines if the elements of this `Iterator` are lexicographically
/// less or equal to those of another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn le<I>(mut self, other: I) -> bool where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
/// Determines if the elements of this `Iterator` are lexicographically
/// greater than those of another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn gt<I>(mut self, other: I) -> bool where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
/// Determines if the elements of this `Iterator` are lexicographically
/// greater than or equal to those of another.
- #[unstable(feature = "iter_order", reason = "needs review and revision", issue = "27737")]
+ #[stable(feature = "iter_order", since = "1.5.0")]
fn ge<I>(mut self, other: I) -> bool where
I: IntoIterator,
Self::Item: PartialOrd<I::Item>,
///
/// This is an idiosyncratic helper to try to factor out the
/// commonalities of {max,min}{,_by}. In particular, this avoids
-/// having to implement optimisations several times.
+/// having to implement optimizations several times.
#[inline]
fn select_fold1<I,B, FProj, FCmp>(mut it: I,
mut f_proj: FProj,
fn size_hint(&self) -> (usize, Option<usize>) { (**self).size_hint() }
}
-/// Conversion from an `Iterator`
+/// Conversion from an `Iterator`.
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_on_unimplemented="a collection of type `{Self}` cannot be \
built from an iterator over elements of type `{A}`"]
-pub trait FromIterator<A> {
+pub trait FromIterator<A>: Sized {
/// Builds a container with elements from something iterable.
///
/// # Examples
fn from_iter<T: IntoIterator<Item=A>>(iterator: T) -> Self;
}
-/// Conversion into an `Iterator`
+/// Conversion into an `Iterator`.
+///
+/// By implementing `IntoIterator` for a type, you define how it will be
+/// converted to an iterator. This is common for types which describe a
+/// collection of some kind.
+///
+/// One benefit of implementing `IntoIterator` is that your type will [work
+/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator).
///
-/// Implementing this trait allows you to use your type with Rust's `for` loop. See
-/// the [module level documentation](index.html) for more details.
+/// # Examples
+///
+/// Vectors implement `IntoIterator`:
+///
+/// ```
+/// let v = vec![1, 2, 3];
+///
+/// let mut iter = v.into_iter();
+///
+/// let n = iter.next();
+/// assert_eq!(Some(1), n);
+///
+/// let n = iter.next();
+/// assert_eq!(Some(2), n);
+///
+/// let n = iter.next();
+/// assert_eq!(Some(3), n);
+///
+/// let n = iter.next();
+/// assert_eq!(None, n);
+/// ```
+///
+/// Implementing `IntoIterator` for your type:
+///
+/// ```
+/// // A sample collection, that's just a wrapper over Vec<T>
+/// #[derive(Debug)]
+/// struct MyCollection(Vec<i32>);
+///
+/// // Let's give it some methods so we can create one and add things
+/// // to it.
+/// impl MyCollection {
+/// fn new() -> MyCollection {
+/// MyCollection(Vec::new())
+/// }
+///
+/// fn add(&mut self, elem: i32) {
+/// self.0.push(elem);
+/// }
+/// }
+///
+/// // and we'll implement IntoIterator
+/// impl IntoIterator for MyCollection {
+/// type Item = i32;
+/// type IntoIter = ::std::vec::IntoIter<i32>;
+///
+/// fn into_iter(self) -> Self::IntoIter {
+/// self.0.into_iter()
+/// }
+/// }
+///
+/// // Now we can make a new collection...
+/// let mut c = MyCollection::new();
+///
+/// // ... add some stuff to it ...
+/// c.add(0);
+/// c.add(1);
+/// c.add(2);
+///
+/// // ... and then turn it into an Iterator:
+/// for (i, n) in c.into_iter().enumerate() {
+/// assert_eq!(i as i32, n);
+/// }
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoIterator {
- /// The type of the elements being iterated
+ /// The type of the elements being iterated over.
#[stable(feature = "rust1", since = "1.0.0")]
type Item;
- /// A container for iterating over elements of type `Item`
+ /// Which kind of iterator are we turning this into?
#[stable(feature = "rust1", since = "1.0.0")]
type IntoIter: Iterator<Item=Self::Item>;
- /// Consumes `Self` and returns an iterator over it
+ /// Consumes `Self` and returns an iterator over it.
#[stable(feature = "rust1", since = "1.0.0")]
fn into_iter(self) -> Self::IntoIter;
}
}
}
-/// A type growable from an `Iterator` implementation
+/// Extend a collection with the contents of an iterator.
+///
+/// Iterators produce a series of values, and collections can also be thought
+/// of as a series of values. The `Extend` trait bridges this gap, allowing you
+/// to extend a collection by including the contents of that iterator.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // You can extend a String with some chars:
+/// let mut message = String::from("The first three letters are: ");
+///
+/// message.extend(&['a', 'b', 'c']);
+///
+/// assert_eq!("abc", &message[29..32]);
+/// ```
+///
+/// Implementing `Extend`:
+///
+/// ```
+/// // A sample collection, that's just a wrapper over Vec<T>
+/// #[derive(Debug)]
+/// struct MyCollection(Vec<i32>);
+///
+/// // Let's give it some methods so we can create one and add things
+/// // to it.
+/// impl MyCollection {
+/// fn new() -> MyCollection {
+/// MyCollection(Vec::new())
+/// }
+///
+/// fn add(&mut self, elem: i32) {
+/// self.0.push(elem);
+/// }
+/// }
+///
+/// // since MyCollection has a list of i32s, we implement Extend for i32
+/// impl Extend<i32> for MyCollection {
+///
+/// // This is a bit simpler with the concrete type signature: we can call
+/// // extend on anything which can be turned into an Iterator which gives
+/// // us i32s. Because we need i32s to put into MyCollection.
+/// fn extend<T: IntoIterator<Item=i32>>(&mut self, iterable: T) {
+///
+/// // The implementation is very straightforward: loop through the
+/// // iterator, and add() each element to ourselves.
+/// for elem in iterable {
+/// self.add(elem);
+/// }
+/// }
+/// }
+///
+/// let mut c = MyCollection::new();
+///
+/// c.add(5);
+/// c.add(6);
+/// c.add(7);
+///
+/// // let's extend our collection with three more numbers
+/// c.extend(vec![1, 2, 3]);
+///
+/// // we've added these elements onto the end
+/// assert_eq!("MyCollection([5, 6, 7, 1, 2, 3])", format!("{:?}", c));
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Extend<A> {
- /// Extends a container with the elements yielded by an arbitrary iterator
+ /// Extends a collection with the contents of an iterator.
+ ///
+ /// As this is the only method for this trait, the [trait-level] docs
+ /// contain more details.
+ ///
+ /// [trait-level]: trait.Extend.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// // You can extend a String with some chars:
+ /// let mut message = String::from("The first three letters are: ");
+ ///
+ /// message.extend(['a', 'b', 'c'].iter());
+ ///
+ /// assert_eq!("abc", &message[29..32]);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn extend<T: IntoIterator<Item=A>>(&mut self, iterable: T);
}
-/// A range iterator able to yield elements from both ends
+/// An iterator able to yield elements from both ends.
+///
+/// Something that implements `DoubleEndedIterator` has one extra capability
+/// over something that implements [`Iterator`]: the ability to also take
+/// `Item`s from the back, as well as the front.
+///
+/// It is important to note that both back and forth work on the same range,
+/// and do not cross: iteration is over when they meet in the middle.
+///
+/// [`Iterator`]: trait.Iterator.html
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// let numbers = vec![1, 2, 3];
+///
+/// let mut iter = numbers.iter();
+///
+/// let n = iter.next();
+/// assert_eq!(Some(&1), n);
+///
+/// let n = iter.next_back();
+/// assert_eq!(Some(&3), n);
///
-/// A `DoubleEndedIterator` can be thought of as a deque in that `next()` and
-/// `next_back()` exhaust elements from the *same* range, and do not work
-/// independently of each other.
+/// let n = iter.next_back();
+/// assert_eq!(Some(&2), n);
+///
+/// let n = iter.next();
+/// assert_eq!(None, n);
+///
+/// let n = iter.next_back();
+/// assert_eq!(None, n);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait DoubleEndedIterator: Iterator {
- /// Yields an element from the end of the range, returning `None` if the
- /// range is empty.
+ /// An iterator able to yield elements from both ends.
+ ///
+ /// As this is the only method for this trait, the [trait-level] docs
+ /// contain more details.
+ ///
+ /// [trait-level]: trait.DoubleEndedIterator.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let numbers = vec![1, 2, 3];
+ ///
+ /// let mut iter = numbers.iter();
+ ///
+ /// let n = iter.next();
+ /// assert_eq!(Some(&1), n);
+ ///
+ /// let n = iter.next_back();
+ /// assert_eq!(Some(&3), n);
+ ///
+ /// let n = iter.next_back();
+ /// assert_eq!(Some(&2), n);
+ ///
+ /// let n = iter.next();
+ /// assert_eq!(None, n);
+ ///
+ /// let n = iter.next_back();
+ /// assert_eq!(None, n);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn next_back(&mut self) -> Option<Self::Item>;
}
fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
}
-/// An iterator that knows its exact length
+/// An iterator that knows its exact length.
+///
+/// Many [`Iterator`]s don't know how many times they will iterate, but some do.
+/// If an iterator knows how many times it can iterate, providing access to
+/// that information can be useful. For example, if you want to iterate
+/// backwards, a good start is to know where the end is.
///
-/// This trait is a helper for iterators like the vector iterator, so that
-/// it can support double-ended enumeration.
+/// When implementing an `ExactSizeIterator`, You must also implement
+/// [`Iterator`]. When doing so, the implementation of [`size_hint()`] *must*
+/// return the exact size of the iterator.
///
-/// `Iterator::size_hint` *must* return the exact size of the iterator.
-/// Note that the size must fit in `usize`.
+/// [`Iterator`]: trait.Iterator.html
+/// [`size_hint()`]: trait.Iterator.html#method.size_hint
+///
+/// The [`len()`] method has a default implementation, so you usually shouldn't
+/// implement it. However, you may be able to provide a more performant
+/// implementation than the default, so overriding it in this case makes sense.
+///
+/// [`len()`]: #method.len
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// // a finite range knows exactly how many times it will iterate
+/// let five = (0..5);
+///
+/// assert_eq!(5, five.len());
+/// ```
+///
+/// In the [module level docs][moddocs], we implemented an [`Iterator`],
+/// `Counter`. Let's implement `ExactSizeIterator` for it as well:
+///
+/// [moddocs]: index.html
+///
+/// ```
+/// # struct Counter {
+/// # count: usize,
+/// # }
+/// # impl Counter {
+/// # fn new() -> Counter {
+/// # Counter { count: 0 }
+/// # }
+/// # }
+/// # impl Iterator for Counter {
+/// # type Item = usize;
+/// # fn next(&mut self) -> Option<usize> {
+/// # self.count += 1;
+/// # if self.count < 6 {
+/// # Some(self.count)
+/// # } else {
+/// # None
+/// # }
+/// # }
+/// # }
+/// impl ExactSizeIterator for Counter {
+/// // We already have the number of iterations, so we can use it directly.
+/// fn len(&self) -> usize {
+/// self.count
+/// }
+/// }
+///
+/// // And now we can use it!
+///
+/// let counter = Counter::new();
+///
+/// assert_eq!(0, counter.len());
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExactSizeIterator: Iterator {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
- /// Returns the exact length of the iterator.
+ /// Returns the exact number of times the iterator will iterate.
+ ///
+ /// This method has a default implementation, so you usually should not
+ /// implement it directly. However, if you can provide a more efficient
+ /// implementation, you can do so. See the [trait-level] docs for an
+ /// example.
+ ///
+ /// [trait-level]: trait.ExactSizeIterator.html
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// // a finite range knows exactly how many times it will iterate
+ /// let five = (0..5);
+ ///
+ /// assert_eq!(5, five.len());
+ /// ```
fn len(&self) -> usize {
let (lower, upper) = self.size_hint();
// Note: This assertion is overly defensive, but it checks the invariant
impl<A, B> ExactSizeIterator for Zip<A, B>
where A: ExactSizeIterator, B: ExactSizeIterator {}
-/// An double-ended iterator with the direction inverted
+/// An double-ended iterator with the direction inverted.
+///
+/// This `struct` is created by the [`rev()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`rev()`]: trait.Iterator.html#method.rev
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
}
-/// An iterator that clones the elements of an underlying iterator
+/// An iterator that clones the elements of an underlying iterator.
+///
+/// This `struct` is created by the [`cloned()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`cloned()`]: trait.Iterator.html#method.cloned
+/// [`Iterator`]: trait.Iterator.html
#[stable(feature = "iter_cloned", since = "1.1.0")]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Clone)]
where I: ExactSizeIterator<Item=&'a T>, T: Clone
{}
-/// An iterator that repeats endlessly
+/// An iterator that repeats endlessly.
+///
+/// This `struct` is created by the [`cycle()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`cycle()`]: trait.Iterator.html#method.cycle
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// An iterator that strings two iterators together
+/// An iterator that strings two iterators together.
+///
+/// This `struct` is created by the [`chain()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`chain()`]: trait.Iterator.html#method.chain
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
fn last(self) -> Option<A::Item> {
match self.state {
- ChainState::Both => self.b.last().or(self.a.last()),
+ ChainState::Both => {
+ // Must exhaust a before b.
+ let a_last = self.a.last();
+ let b_last = self.b.last();
+ b_last.or(a_last)
+ },
ChainState::Front => self.a.last(),
ChainState::Back => self.b.last()
}
}
}
-/// An iterator that iterates two other iterators simultaneously
+/// An iterator that iterates two other iterators simultaneously.
+///
+/// This `struct` is created by the [`zip()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`zip()`]: trait.Iterator.html#method.zip
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// An iterator that maps the values of `iter` with `f`
+/// An iterator that maps the values of `iter` with `f`.
+///
+/// This `struct` is created by the [`map()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`map()`]: trait.Iterator.html#method.map
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
}
}
-/// An iterator that filters the elements of `iter` with `predicate`
+/// An iterator that filters the elements of `iter` with `predicate`.
+///
+/// This `struct` is created by the [`filter()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`filter()`]: trait.Iterator.html#method.filter
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
}
}
-/// An iterator that uses `f` to both filter and map elements from `iter`
+/// An iterator that uses `f` to both filter and map elements from `iter`.
+///
+/// This `struct` is created by the [`filter_map()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`filter_map()`]: trait.Iterator.html#method.filter_map
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
}
}
-/// An iterator that yields the current count and the element during iteration
+/// An iterator that yields the current count and the element during iteration.
+///
+/// This `struct` is created by the [`enumerate()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`enumerate()`]: trait.Iterator.html#method.enumerate
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/// An iterator with a `peek()` that returns an optional reference to the next element.
+/// An iterator with a `peek()` that returns an optional reference to the next
+/// element.
+///
+/// This `struct` is created by the [`peekable()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`peekable()`]: trait.Iterator.html#method.peekable
+/// [`Iterator`]: trait.Iterator.html
+#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Peekable<I: Iterator> {
peeked: Option<I::Item>,
}
-impl<I: Iterator + Clone> Clone for Peekable<I> where I::Item: Clone {
- fn clone(&self) -> Peekable<I> {
- Peekable {
- iter: self.iter.clone(),
- peeked: self.peeked.clone(),
- }
- }
-}
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<I: Iterator> Iterator for Peekable<I> {
type Item = I::Item;
}
}
-/// An iterator that rejects elements while `predicate` is true
+/// An iterator that rejects elements while `predicate` is true.
+///
+/// This `struct` is created by the [`skip_while()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`skip_while()`]: trait.Iterator.html#method.skip_while
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
}
}
-/// An iterator that only accepts elements while `predicate` is true
+/// An iterator that only accepts elements while `predicate` is true.
+///
+/// This `struct` is created by the [`take_while()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`take_while()`]: trait.Iterator.html#method.take_while
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
}
/// An iterator that skips over `n` elements of `iter`.
+///
+/// This `struct` is created by the [`skip()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`skip()`]: trait.Iterator.html#method.skip
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Skip<I> where I: ExactSizeIterator {}
/// An iterator that only iterates over the first `n` iterations of `iter`.
+///
+/// This `struct` is created by the [`take()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`take()`]: trait.Iterator.html#method.take
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
-/// An iterator to maintain state while iterating another iterator
+/// An iterator to maintain state while iterating another iterator.
+///
+/// This `struct` is created by the [`scan()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`scan()`]: trait.Iterator.html#method.scan
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
}
}
-/// An iterator that maps each element to an iterator,
-/// and yields the elements of the produced iterators
+/// An iterator that maps each element to an iterator, and yields the elements
+/// of the produced iterators.
+///
+/// This `struct` is created by the [`flat_map()`] method on [`Iterator`]. See its
+/// documentation for more.
///
+/// [`flat_map()`]: trait.Iterator.html#method.flat_map
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
+///
+/// This `struct` is created by the [`fuse()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`fuse()`]: trait.Iterator.html#method.fuse
+/// [`Iterator`]: trait.Iterator.html
#[derive(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I> where I: ExactSizeIterator {}
-/// An iterator that calls a function with a reference to each
-/// element before yielding it.
+/// An iterator that calls a function with a reference to each element before
+/// yielding it.
+///
+/// This `struct` is created by the [`inspect()`] method on [`Iterator`]. See its
+/// documentation for more.
+///
+/// [`inspect()`]: trait.Iterator.html#method.inspect
+/// [`Iterator`]: trait.Iterator.html
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Clone)]
#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters",
issue = "27777")]
+#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
+#[allow(deprecated)]
pub struct RangeInclusive<A> {
range: ops::Range<A>,
done: bool,
#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters",
issue = "27777")]
+#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
+#[allow(deprecated)]
pub fn range_inclusive<A>(start: A, stop: A) -> RangeInclusive<A>
where A: Step + One + Clone
{
#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters",
issue = "27777")]
+#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
+#[allow(deprecated)]
impl<A> Iterator for RangeInclusive<A> where
A: PartialEq + Step + One + Clone,
for<'a> &'a A: Add<&'a A, Output = A>
#[unstable(feature = "range_inclusive",
reason = "likely to be replaced by range notation and adapters",
issue = "27777")]
+#[deprecated(since = "1.5.0", reason = "replaced with ... syntax")]
+#[allow(deprecated)]
impl<A> DoubleEndedIterator for RangeInclusive<A> where
A: PartialEq + Step + One + Clone,
for<'a> &'a A: Add<&'a A, Output = A>,
}
}
-/// An iterator that repeats an element endlessly
+/// An iterator that repeats an element endlessly.
+///
+/// This `struct` is created by the [`repeat()`] function. See its documentation for more.
+///
+/// [`repeat()`]: fn.repeat.html
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Repeat<A> {
fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
}
-/// Creates a new iterator that endlessly repeats the element `elt`.
+/// Creates a new iterator that endlessly repeats a single element.
+///
+/// The `repeat()` function repeats a single value over and over and over and
+/// over and over and 🔁.
+///
+/// Infinite iterators like `repeat()` are often used with adapters like
+/// [`take()`], in order to make them finite.
+///
+/// [`take()`]: trait.Iterator.html#method.take
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // the number four 4ever:
+/// let mut fours = iter::repeat(4);
+///
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+/// assert_eq!(Some(4), fours.next());
+///
+/// // yup, still four
+/// assert_eq!(Some(4), fours.next());
+/// ```
+///
+/// Going finite with [`take()`]:
+///
+/// ```
+/// use std::iter;
+///
+/// // that last example was too many fours. Let's only have four fours.
+/// let mut four_fours = iter::repeat(4).take(4);
+///
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+/// assert_eq!(Some(4), four_fours.next());
+///
+/// // ... and now we're done
+/// assert_eq!(None, four_fours.next());
+/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn repeat<T: Clone>(elt: T) -> Repeat<T> {
}
/// An iterator that yields nothing.
+///
+/// This `struct` is created by the [`empty()`] function. See its documentation for more.
+///
+/// [`empty()`]: fn.empty.html
#[stable(feature = "iter_empty", since = "1.2.0")]
pub struct Empty<T>(marker::PhantomData<T>);
}
/// Creates an iterator that yields nothing.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // this could have been an iterator over i32, but alas, it's just not.
+/// let mut nope = iter::empty::<i32>();
+///
+/// assert_eq!(None, nope.next());
+/// ```
#[stable(feature = "iter_empty", since = "1.2.0")]
pub fn empty<T>() -> Empty<T> {
Empty(marker::PhantomData)
}
/// An iterator that yields an element exactly once.
+///
+/// This `struct` is created by the [`once()`] function. See its documentation for more.
+///
+/// [`once()`]: fn.once.html
#[derive(Clone)]
#[stable(feature = "iter_once", since = "1.2.0")]
pub struct Once<T> {
}
/// Creates an iterator that yields an element exactly once.
+///
+/// This is commonly used to adapt a single value into a [`chain()`] of other
+/// kinds of iteration. Maybe you have an iterator that covers almost
+/// everything, but you need an extra special case. Maybe you have a function
+/// which works on iterators, but you only need to process one value.
+///
+/// [`chain()`]: trait.Iterator.html#method.chain
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::iter;
+///
+/// // one is the loneliest number
+/// let mut one = iter::once(1);
+///
+/// assert_eq!(Some(1), one.next());
+///
+/// // just one, that's all we get
+/// assert_eq!(None, one.next());
+/// ```
+///
+/// Chaining together with another iterator. Let's say that we want to iterate
+/// over each file of the `.foo` directory, but also a configuration file,
+/// `.foorc`:
+///
+/// ```no_run
+/// use std::iter;
+/// use std::fs;
+/// use std::path::PathBuf;
+///
+/// let dirs = fs::read_dir(".foo").unwrap();
+///
+/// // we need to convert from an iterator of DirEntry-s to an iterator of
+/// // PathBufs, so we use map
+/// let dirs = dirs.map(|file| file.unwrap().path());
+///
+/// // now, our iterator just for our config file
+/// let config = iter::once(PathBuf::from(".foorc"));
+///
+/// // chain the two iterators together into one big iterator
+/// let files = dirs.chain(config);
+///
+/// // this will give us all of the files in .foo as well as .foorc
+/// for f in files {
+/// println!("{:?}", f);
+/// }
+/// ```
#[stable(feature = "iter_once", since = "1.2.0")]
pub fn once<T>(value: T) -> Once<T> {
Once { inner: Some(value).into_iter() }
/// If two sequences are equal up until the point where one ends,
/// the shorter sequence compares less.
#[deprecated(since = "1.4.0", reason = "use the equivalent methods on `Iterator` instead")]
-#[unstable(feature = "iter_order", reason = "needs review and revision",
+#[unstable(feature = "iter_order_deprecated", reason = "needs review and revision",
issue = "27737")]
pub mod order {
use cmp;
})
}
-/// Use the `format!` syntax to write data into a buffer of type `&mut Write`.
-/// See `std::fmt` for more information.
+/// Use the `format!` syntax to write data into a buffer.
+///
+/// This macro is typically used with a buffer of `&mut `[`Write`][write].
+///
+/// See [`std::fmt`][fmt] for more information on format syntax.
+///
+/// [fmt]: fmt/index.html
+/// [write]: io/trait.Write.html
///
/// # Examples
///
/// let mut w = Vec::new();
/// write!(&mut w, "test").unwrap();
/// write!(&mut w, "formatted {}", "arguments").unwrap();
+///
+/// assert_eq!(w, b"testformatted arguments");
/// ```
#[macro_export]
macro_rules! write {
($dst:expr, $($arg:tt)*) => ($dst.write_fmt(format_args!($($arg)*)))
}
-/// Equivalent to the `write!` macro, except that a newline is appended after
-/// the message is written.
+/// Use the `format!` syntax to write data into a buffer, appending a newline.
+///
+/// This macro is typically used with a buffer of `&mut `[`Write`][write].
+///
+/// See [`std::fmt`][fmt] for more information on format syntax.
+///
+/// [fmt]: fmt/index.html
+/// [write]: io/trait.Write.html
+///
+/// # Examples
+///
+/// ```
+/// use std::io::Write;
+///
+/// let mut w = Vec::new();
+/// writeln!(&mut w, "test").unwrap();
+/// writeln!(&mut w, "formatted {}", "arguments").unwrap();
+///
+/// assert_eq!(&w[..], "test\nformatted arguments\n".as_bytes());
+/// ```
#[macro_export]
#[stable(feature = "rust1", since = "1.0.0")]
macro_rules! writeln {
});
}
-/// A standardised placeholder for marking unfinished code. It panics with the
+/// A standardized placeholder for marking unfinished code. It panics with the
/// message `"not yet implemented"` when executed.
///
/// This can be useful if you are prototyping and are just looking to have your
impl<T> !Send for *mut T { }
/// Types with a constant size known at compile-time.
+///
+/// All type parameters which can be bounded have an implicit bound of `Sized`. The special syntax
+/// `?Sized` can be used to remove this bound if it is not appropriate.
+///
+/// ```
+/// struct Foo<T>(T);
+/// struct Bar<T: ?Sized>(T);
+///
+/// // struct FooUse(Foo<[i32]>); // error: Sized is not implemented for [i32]
+/// struct BarUse(Bar<[i32]>); // OK
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sized"]
#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"]
///
/// A somewhat surprising consequence of the definition is `&mut T` is
/// `Sync` (if `T` is `Sync`) even though it seems that it might
-/// provide unsynchronised mutation. The trick is a mutable reference
+/// provide unsynchronized mutation. The trick is a mutable reference
/// stored in an aliasable reference (that is, `& &mut T`) becomes
/// read-only, as if it were a `& &T`, hence there is no risk of a data
/// race.
///
/// Any types with interior mutability must also use the `std::cell::UnsafeCell`
/// wrapper around the value(s) which can be mutated when behind a `&`
-/// reference; not doing this is undefined behaviour (for example,
+/// reference; not doing this is undefined behavior (for example,
/// `transmute`-ing from `&T` to `&mut T` is invalid).
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "sync"]
/// ```
///
/// Without the declaration `T:Reflect`, `foo` would not type check
-/// (note: as a matter of style, it would be preferable to to write
+/// (note: as a matter of style, it would be preferable to write
/// `T:Any`, because `T:Any` implies `T:Reflect` and `T:'static`, but
/// we use `Reflect` here to show how it works). The `Reflect` bound
/// thus serves to alert `foo`'s caller to the fact that `foo` may
/// * You have two copies of a value (like when writing something like
/// [`mem::swap`][swap]), but need the destructor to only run once to
/// prevent a double `free`.
-/// * Transferring resources across [FFI][ffi] boundries.
+/// * Transferring resources across [FFI][ffi] boundaries.
///
/// [swap]: fn.swap.html
/// [ffi]: ../../book/ffi.html
/// This is useful for FFI functions and initializing arrays sometimes,
/// but should generally be avoided.
///
-/// # Undefined Behaviour
+/// # Undefined Behavior
///
-/// It is Undefined Behaviour to read uninitialized memory. Even just an
+/// It is Undefined Behavior to read uninitialized memory. Even just an
/// uninitialized boolean. For instance, if you branch on the value of such
/// a boolean your program may take one, both, or neither of the branches.
///
///
/// // DANGER ZONE: if anything panics or otherwise
/// // incorrectly reads the array here, we will have
-/// // Undefined Behaviour.
+/// // Undefined Behavior.
///
/// // It's ok to mutably iterate the data, since this
/// // doesn't involve reading it at all.
intrinsics::uninit()
}
-/// Swap the values at two mutable locations of the same type, without deinitialising or copying
+/// Swap the values at two mutable locations of the same type, without deinitializing or copying
/// either one.
///
/// # Examples
}
/// Replaces the value at a mutable location with a new one, returning the old value, without
-/// deinitialising or copying either one.
+/// deinitializing or copying either one.
///
/// This is primarily used for transferring and swapping ownership of a value in a mutable
/// location.
/// While this does call the argument's implementation of `Drop`, it will not
/// release any borrows, as borrows are based on lexical scope.
///
+/// This effectively does nothing for
+/// [types which implement `Copy`](../../book/ownership.html#copy-types),
+/// e.g. integers. Such values are copied and _then_ moved into the function,
+/// so the value persists after this function call.
+///
/// # Examples
///
/// Basic usage:
/// let borrow = x.borrow();
/// println!("{}", *borrow);
/// ```
+///
+/// Integers and other types implementing `Copy` are unaffected by `drop()`
+///
+/// ```
+/// #[derive(Copy, Clone)]
+/// struct Foo(u8);
+///
+/// let x = 1;
+/// let y = Foo(2);
+/// drop(x); // a copy of `x` is moved and dropped
+/// drop(y); // a copy of `y` is moved and dropped
+///
+/// println!("x: {}, y: {}", x, y.0); // still available
+/// ```
+///
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn drop<T>(_x: T) { }
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct NonZero<T: Zeroable>(T);
+#[cfg(stage0)]
+macro_rules! nonzero_new {
+ () => (
+ /// Creates an instance of NonZero with the provided value.
+ /// You must indeed ensure that the value is actually "non-zero".
+ #[inline(always)]
+ pub unsafe fn new(inner: T) -> NonZero<T> {
+ NonZero(inner)
+ }
+ )
+}
+#[cfg(not(stage0))]
+macro_rules! nonzero_new {
+ () => (
+ /// Creates an instance of NonZero with the provided value.
+ /// You must indeed ensure that the value is actually "non-zero".
+ #[inline(always)]
+ pub const unsafe fn new(inner: T) -> NonZero<T> {
+ NonZero(inner)
+ }
+ )
+}
+
impl<T: Zeroable> NonZero<T> {
- /// Creates an instance of NonZero with the provided value.
- /// You must indeed ensure that the value is actually "non-zero".
- #[inline(always)]
- pub unsafe fn new(inner: T) -> NonZero<T> {
- NonZero(inner)
- }
+ nonzero_new!{}
}
impl<T: Zeroable> Deref for NonZero<T> {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Custom arbitrary-precision number (bignum) implementation.
+//!
+//! This is designed to avoid the heap allocation at expense of stack memory.
+//! The most used bignum type, `Big32x40`, is limited by 32 × 40 = 1,280 bits
+//! and will take at most 160 bytes of stack memory. This is more than enough
+//! for round-tripping all possible finite `f64` values.
+//!
+//! In principle it is possible to have multiple bignum types for different
+//! inputs, but we don't do so to avoid the code bloat. Each bignum is still
+//! tracked for the actual usages, so it normally doesn't matter.
+
+// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
+// It is not intended to ever be stabilized.
+#![doc(hidden)]
+#![unstable(feature = "core_private_bignum",
+ reason = "internal routines only exposed for testing",
+ issue = "0")]
+#![macro_use]
+
+use prelude::v1::*;
+
+use mem;
+use intrinsics;
+
+/// Arithmetic operations required by bignums.
+pub trait FullOps {
+ /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
+ /// where `W` is the number of bits in `Self`.
+ fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
+
+ /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
+ /// where `W` is the number of bits in `Self`.
+ fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self);
+
+ /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
+ /// where `W` is the number of bits in `Self`.
+ fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self);
+
+ /// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem`
+ /// and `0 <= rem < other`, where `W` is the number of bits in `Self`.
+ fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/);
+}
+
+macro_rules! impl_full_ops {
+ ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
+ $(
+ impl FullOps for $ty {
+ fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) {
+ // this cannot overflow, the output is between 0 and 2*2^nbits - 1
+ // FIXME will LLVM optimize this into ADC or similar???
+ let (v, carry1) = unsafe { $addfn(self, other) };
+ let (v, carry2) = unsafe { $addfn(v, if carry {1} else {0}) };
+ (carry1 || carry2, v)
+ }
+
+ fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) {
+ // this cannot overflow, the output is between 0 and 2^nbits * (2^nbits - 1)
+ let nbits = mem::size_of::<$ty>() * 8;
+ let v = (self as $bigty) * (other as $bigty) + (carry as $bigty);
+ ((v >> nbits) as $ty, v as $ty)
+ }
+
+ fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
+ // this cannot overflow, the output is between 0 and 2^(2*nbits) - 1
+ let nbits = mem::size_of::<$ty>() * 8;
+ let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) +
+ (carry as $bigty);
+ ((v >> nbits) as $ty, v as $ty)
+ }
+
+ fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) {
+ debug_assert!(borrow < other);
+ // this cannot overflow, the dividend is between 0 and other * 2^nbits - 1
+ let nbits = mem::size_of::<$ty>() * 8;
+ let lhs = ((borrow as $bigty) << nbits) | (self as $bigty);
+ let rhs = other as $bigty;
+ ((lhs / rhs) as $ty, (lhs % rhs) as $ty)
+ }
+ }
+ )*
+ )
+}
+
+impl_full_ops! {
+ u8: add(intrinsics::u8_add_with_overflow), mul/div(u16);
+ u16: add(intrinsics::u16_add_with_overflow), mul/div(u32);
+ u32: add(intrinsics::u32_add_with_overflow), mul/div(u64);
+// u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); // see RFC #521 for enabling this.
+}
+
+/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value
+/// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`.
+const SMALL_POW5: [(u64, usize); 3] = [
+ (125, 3),
+ (15625, 6),
+ (1_220_703_125, 13),
+];
+
+macro_rules! define_bignum {
+ ($name:ident: type=$ty:ty, n=$n:expr) => (
+ /// Stack-allocated arbitrary-precision (up to certain limit) integer.
+ ///
+ /// This is backed by a fixed-size array of given type ("digit").
+ /// While the array is not very large (normally some hundred bytes),
+ /// copying it recklessly may result in the performance hit.
+ /// Thus this is intentionally not `Copy`.
+ ///
+ /// All operations available to bignums panic in the case of over/underflows.
+ /// The caller is responsible to use large enough bignum types.
+ pub struct $name {
+ /// One plus the offset to the maximum "digit" in use.
+ /// This does not decrease, so be aware of the computation order.
+ /// `base[size..]` should be zero.
+ size: usize,
+ /// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...`
+ /// where `W` is the number of bits in the digit type.
+ base: [$ty; $n]
+ }
+
+ impl $name {
+ /// Makes a bignum from one digit.
+ pub fn from_small(v: $ty) -> $name {
+ let mut base = [0; $n];
+ base[0] = v;
+ $name { size: 1, base: base }
+ }
+
+ /// Makes a bignum from `u64` value.
+ pub fn from_u64(mut v: u64) -> $name {
+ use mem;
+
+ let mut base = [0; $n];
+ let mut sz = 0;
+ while v > 0 {
+ base[sz] = v as $ty;
+ v >>= mem::size_of::<$ty>() * 8;
+ sz += 1;
+ }
+ $name { size: sz, base: base }
+ }
+
+ /// Return the internal digits as a slice `[a, b, c, ...]` such that the numeric
+ /// value is `a + b * 2^W + c * 2^(2W) + ...` where `W` is the number of bits in
+ /// the digit type.
+ pub fn digits(&self) -> &[$ty] {
+ &self.base[..self.size]
+ }
+
+ /// Return the `i`-th bit where bit 0 is the least significant one.
+ /// In other words, the bit with weight `2^i`.
+ pub fn get_bit(&self, i: usize) -> u8 {
+ use mem;
+
+ let digitbits = mem::size_of::<$ty>() * 8;
+ let d = i / digitbits;
+ let b = i % digitbits;
+ ((self.base[d] >> b) & 1) as u8
+ }
+
+ /// Returns true if the bignum is zero.
+ pub fn is_zero(&self) -> bool {
+ self.digits().iter().all(|&v| v == 0)
+ }
+
+ /// Returns the number of bits necessary to represent this value. Note that zero
+ /// is considered to need 0 bits.
+ pub fn bit_length(&self) -> usize {
+ use mem;
+
+ // Skip over the most significant digits which are zero.
+ let digits = self.digits();
+ let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
+ let end = digits.len() - zeros;
+ let nonzero = &digits[..end];
+
+ if nonzero.is_empty() {
+ // There are no non-zero digits, i.e. the number is zero.
+ return 0;
+ }
+ // This could be optimized with leading_zeros() and bit shifts, but that's
+ // probably not worth the hassle.
+ let digitbits = mem::size_of::<$ty>()* 8;
+ let mut i = nonzero.len() * digitbits - 1;
+ while self.get_bit(i) == 0 {
+ i -= 1;
+ }
+ i + 1
+ }
+
+ /// Adds `other` to itself and returns its own mutable reference.
+ pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
+ use cmp;
+ use num::bignum::FullOps;
+
+ let mut sz = cmp::max(self.size, other.size);
+ let mut carry = false;
+ for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) {
+ let (c, v) = (*a).full_add(*b, carry);
+ *a = v;
+ carry = c;
+ }
+ if carry {
+ self.base[sz] = 1;
+ sz += 1;
+ }
+ self.size = sz;
+ self
+ }
+
+ pub fn add_small(&mut self, other: $ty) -> &mut $name {
+ use num::bignum::FullOps;
+
+ let (mut carry, v) = self.base[0].full_add(other, false);
+ self.base[0] = v;
+ let mut i = 1;
+ while carry {
+ let (c, v) = self.base[i].full_add(0, carry);
+ self.base[i] = v;
+ carry = c;
+ i += 1;
+ }
+ if i > self.size {
+ self.size = i;
+ }
+ self
+ }
+
+ /// Subtracts `other` from itself and returns its own mutable reference.
+ pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
+ use cmp;
+ use num::bignum::FullOps;
+
+ let sz = cmp::max(self.size, other.size);
+ let mut noborrow = true;
+ for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) {
+ let (c, v) = (*a).full_add(!*b, noborrow);
+ *a = v;
+ noborrow = c;
+ }
+ assert!(noborrow);
+ self.size = sz;
+ self
+ }
+
+ /// Multiplies itself by a digit-sized `other` and returns its own
+ /// mutable reference.
+ pub fn mul_small(&mut self, other: $ty) -> &mut $name {
+ use num::bignum::FullOps;
+
+ let mut sz = self.size;
+ let mut carry = 0;
+ for a in &mut self.base[..sz] {
+ let (c, v) = (*a).full_mul(other, carry);
+ *a = v;
+ carry = c;
+ }
+ if carry > 0 {
+ self.base[sz] = carry;
+ sz += 1;
+ }
+ self.size = sz;
+ self
+ }
+
+ /// Multiplies itself by `2^bits` and returns its own mutable reference.
+ pub fn mul_pow2(&mut self, bits: usize) -> &mut $name {
+ use mem;
+
+ let digitbits = mem::size_of::<$ty>() * 8;
+ let digits = bits / digitbits;
+ let bits = bits % digitbits;
+
+ assert!(digits < $n);
+ debug_assert!(self.base[$n-digits..].iter().all(|&v| v == 0));
+ debug_assert!(bits == 0 || (self.base[$n-digits-1] >> (digitbits - bits)) == 0);
+
+ // shift by `digits * digitbits` bits
+ for i in (0..self.size).rev() {
+ self.base[i+digits] = self.base[i];
+ }
+ for i in 0..digits {
+ self.base[i] = 0;
+ }
+
+ // shift by `bits` bits
+ let mut sz = self.size + digits;
+ if bits > 0 {
+ let last = sz;
+ let overflow = self.base[last-1] >> (digitbits - bits);
+ if overflow > 0 {
+ self.base[last] = overflow;
+ sz += 1;
+ }
+ for i in (digits+1..last).rev() {
+ self.base[i] = (self.base[i] << bits) |
+ (self.base[i-1] >> (digitbits - bits));
+ }
+ self.base[digits] <<= bits;
+ // self.base[..digits] is zero, no need to shift
+ }
+
+ self.size = sz;
+ self
+ }
+
+ /// Multiplies itself by `5^e` and returns its own mutable reference.
+ pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name {
+ use mem;
+ use num::bignum::SMALL_POW5;
+
+ // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes
+ // are consecutive powers of two, so this is well suited index for the table.
+ let table_index = mem::size_of::<$ty>().trailing_zeros() as usize;
+ let (small_power, small_e) = SMALL_POW5[table_index];
+ let small_power = small_power as $ty;
+
+ // Multiply with the largest single-digit power as long as possible ...
+ while e >= small_e {
+ self.mul_small(small_power);
+ e -= small_e;
+ }
+
+ // ... then finish off the remainder.
+ let mut rest_power = 1;
+ for _ in 0..e {
+ rest_power *= 5;
+ }
+ self.mul_small(rest_power);
+
+ self
+ }
+
+
+ /// Multiplies itself by a number described by `other[0] + other[1] * 2^W +
+ /// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type)
+ /// and returns its own mutable reference.
+ pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name {
+ // the internal routine. works best when aa.len() <= bb.len().
+ fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize {
+ use num::bignum::FullOps;
+
+ let mut retsz = 0;
+ for (i, &a) in aa.iter().enumerate() {
+ if a == 0 { continue; }
+ let mut sz = bb.len();
+ let mut carry = 0;
+ for (j, &b) in bb.iter().enumerate() {
+ let (c, v) = a.full_mul_add(b, ret[i + j], carry);
+ ret[i + j] = v;
+ carry = c;
+ }
+ if carry > 0 {
+ ret[i + sz] = carry;
+ sz += 1;
+ }
+ if retsz < i + sz {
+ retsz = i + sz;
+ }
+ }
+ retsz
+ }
+
+ let mut ret = [0; $n];
+ let retsz = if self.size < other.len() {
+ mul_inner(&mut ret, &self.digits(), other)
+ } else {
+ mul_inner(&mut ret, other, &self.digits())
+ };
+ self.base = ret;
+ self.size = retsz;
+ self
+ }
+
+ /// Divides itself by a digit-sized `other` and returns its own
+ /// mutable reference *and* the remainder.
+ pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) {
+ use num::bignum::FullOps;
+
+ assert!(other > 0);
+
+ let sz = self.size;
+ let mut borrow = 0;
+ for a in self.base[..sz].iter_mut().rev() {
+ let (q, r) = (*a).full_div_rem(other, borrow);
+ *a = q;
+ borrow = r;
+ }
+ (self, borrow)
+ }
+
+ /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the
+ /// remainder.
+ pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) {
+ use mem;
+
+ // Stupid slow base-2 long division taken from
+ // https://en.wikipedia.org/wiki/Division_algorithm
+ // FIXME use a greater base ($ty) for the long division.
+ assert!(!d.is_zero());
+ let digitbits = mem::size_of::<$ty>() * 8;
+ for digit in &mut q.base[..] {
+ *digit = 0;
+ }
+ for digit in &mut r.base[..] {
+ *digit = 0;
+ }
+ r.size = d.size;
+ q.size = 1;
+ let mut q_is_zero = true;
+ let end = self.bit_length();
+ for i in (0..end).rev() {
+ r.mul_pow2(1);
+ r.base[0] |= self.get_bit(i) as $ty;
+ if &*r >= d {
+ r.sub(d);
+ // Set bit `i` of q to 1.
+ let digit_idx = i / digitbits;
+ let bit_idx = i % digitbits;
+ if q_is_zero {
+ q.size = digit_idx + 1;
+ q_is_zero = false;
+ }
+ q.base[digit_idx] |= 1 << bit_idx;
+ }
+ }
+ debug_assert!(q.base[q.size..].iter().all(|&d| d == 0));
+ debug_assert!(r.base[r.size..].iter().all(|&d| d == 0));
+ }
+ }
+
+ impl ::cmp::PartialEq for $name {
+ fn eq(&self, other: &$name) -> bool { self.base[..] == other.base[..] }
+ }
+
+ impl ::cmp::Eq for $name {
+ }
+
+ impl ::cmp::PartialOrd for $name {
+ fn partial_cmp(&self, other: &$name) -> ::option::Option<::cmp::Ordering> {
+ ::option::Option::Some(self.cmp(other))
+ }
+ }
+
+ impl ::cmp::Ord for $name {
+ fn cmp(&self, other: &$name) -> ::cmp::Ordering {
+ use cmp::max;
+ let sz = max(self.size, other.size);
+ let lhs = self.base[..sz].iter().cloned().rev();
+ let rhs = other.base[..sz].iter().cloned().rev();
+ lhs.cmp(rhs)
+ }
+ }
+
+ impl ::clone::Clone for $name {
+ fn clone(&self) -> $name {
+ $name { size: self.size, base: self.base }
+ }
+ }
+
+ impl ::fmt::Debug for $name {
+ fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+ use mem;
+
+ let sz = if self.size < 1 {1} else {self.size};
+ let digitlen = mem::size_of::<$ty>() * 2;
+
+ try!(write!(f, "{:#x}", self.base[sz-1]));
+ for &v in self.base[..sz-1].iter().rev() {
+ try!(write!(f, "_{:01$x}", v, digitlen));
+ }
+ ::result::Result::Ok(())
+ }
+ }
+ )
+}
+
+/// The digit type for `Big32x40`.
+pub type Digit32 = u32;
+
+define_bignum!(Big32x40: type=Digit32, n=40);
+
+// this one is used for testing only.
+#[doc(hidden)]
+pub mod tests {
+ use prelude::v1::*;
+ define_bignum!(Big8x3: type=u8, n=3);
+}
//! The various algorithms from the paper.
-use num::flt2dec::strategy::grisu::Fp;
use prelude::v1::*;
use cmp::min;
use cmp::Ordering::{Less, Equal, Greater};
-use super::table;
-use super::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float};
-use super::num::{self, Big};
+use num::diy_float::Fp;
+use num::dec2flt::table;
+use num::dec2flt::rawfp::{self, Unpacked, RawFloat, fp_to_float, next_float, prev_float};
+use num::dec2flt::num::{self, Big};
/// Number of significand bits in Fp
const P: u32 = 64;
//! "such that the exponent +/- the number of decimal digits fits into a 64 bit integer".
//! Larger exponents are accepted, but we don't do arithmetic with them, they are immediately
//! turned into {positive,negative} {zero,infinity}.
-//!
-//! FIXME: this uses several things from core::num::flt2dec, which is nonsense. Those things
-//! should be moved into core::num::<something else>.
#![doc(hidden)]
#![unstable(feature = "dec2flt",
use prelude::v1::*;
use cmp::Ordering::{self, Less, Equal, Greater};
-use num::flt2dec::bignum::Big32x40;
-pub type Big = Big32x40;
+pub use num::bignum::Big32x40 as Big;
/// Test whether truncating all bits less significant than `ones_place` introduces
/// a relative error less, equal, or greater than 0.5 ULP.
use ops::{Mul, Div, Neg};
use fmt::{Debug, LowerExp};
use mem::transmute;
-use num::flt2dec::strategy::grisu::Fp;
+use num::diy_float::Fp;
use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan};
use num::Float;
-use super::num::{self, Big};
+use num::dec2flt::num::{self, Big};
#[derive(Copy, Clone, Debug)]
pub struct Unpacked {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Extended precision "soft float", for internal use only.
+
+// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
+// It is not intended to ever be stabilized.
+#![doc(hidden)]
+#![unstable(feature = "core_private_diy_float",
+ reason = "internal routines only exposed for testing",
+ issue = "0")]
+
+/// A custom 64-bit floating point type, representing `f * 2^e`.
+#[derive(Copy, Clone, Debug)]
+#[doc(hidden)]
+pub struct Fp {
+ /// The integer mantissa.
+ pub f: u64,
+ /// The exponent in base 2.
+ pub e: i16,
+}
+
+impl Fp {
+ /// Returns a correctly rounded product of itself and `other`.
+ pub fn mul(&self, other: &Fp) -> Fp {
+ const MASK: u64 = 0xffffffff;
+ let a = self.f >> 32;
+ let b = self.f & MASK;
+ let c = other.f >> 32;
+ let d = other.f & MASK;
+ let ac = a * c;
+ let bc = b * c;
+ let ad = a * d;
+ let bd = b * d;
+ let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */;
+ let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
+ let e = self.e + other.e + 64;
+ Fp { f: f, e: e }
+ }
+
+ /// Normalizes itself so that the resulting mantissa is at least `2^63`.
+ pub fn normalize(&self) -> Fp {
+ let mut f = self.f;
+ let mut e = self.e;
+ if f >> (64 - 32) == 0 { f <<= 32; e -= 32; }
+ if f >> (64 - 16) == 0 { f <<= 16; e -= 16; }
+ if f >> (64 - 8) == 0 { f <<= 8; e -= 8; }
+ if f >> (64 - 4) == 0 { f <<= 4; e -= 4; }
+ if f >> (64 - 2) == 0 { f <<= 2; e -= 2; }
+ if f >> (64 - 1) == 0 { f <<= 1; e -= 1; }
+ debug_assert!(f >= (1 >> 63));
+ Fp { f: f, e: e }
+ }
+
+ /// Normalizes itself to have the shared exponent.
+ /// It can only decrease the exponent (and thus increase the mantissa).
+ pub fn normalize_to(&self, e: i16) -> Fp {
+ let edelta = self.e - e;
+ assert!(edelta >= 0);
+ let edelta = edelta as usize;
+ assert_eq!(self.f << edelta >> edelta, self.f);
+ Fp { f: self.f << edelta, e: e }
+ }
+}
#[allow(missing_docs)]
pub const NEG_INFINITY: f32 = -1.0_f32/0.0_f32;
-/// Basic mathematial constants.
+/// Basic mathematical constants.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod consts {
// FIXME: replace with mathematical constants from cmath.
#[allow(missing_docs)]
pub const NEG_INFINITY: f64 = -1.0_f64/0.0_f64;
-/// Basic mathematial constants.
+/// Basic mathematical constants.
#[stable(feature = "rust1", since = "1.0.0")]
pub mod consts {
// FIXME: replace with mathematical constants from cmath.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Custom arbitrary-precision number (bignum) implementation.
-//!
-//! This is designed to avoid the heap allocation at expense of stack memory.
-//! The most used bignum type, `Big32x40`, is limited by 32 × 40 = 1,280 bits
-//! and will take at most 160 bytes of stack memory. This is more than enough
-//! for round-tripping all possible finite `f64` values.
-//!
-//! In principle it is possible to have multiple bignum types for different
-//! inputs, but we don't do so to avoid the code bloat. Each bignum is still
-//! tracked for the actual usages, so it normally doesn't matter.
-
-#![macro_use]
-
-use prelude::v1::*;
-
-use mem;
-use intrinsics;
-
-/// Arithmetic operations required by bignums.
-pub trait FullOps {
- /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
- /// where `W` is the number of bits in `Self`.
- fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
-
- /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
- /// where `W` is the number of bits in `Self`.
- fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self);
-
- /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
- /// where `W` is the number of bits in `Self`.
- fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self);
-
- /// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem`
- /// and `0 <= rem < other`, where `W` is the number of bits in `Self`.
- fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/);
-}
-
-macro_rules! impl_full_ops {
- ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
- $(
- impl FullOps for $ty {
- fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) {
- // this cannot overflow, the output is between 0 and 2*2^nbits - 1
- // FIXME will LLVM optimize this into ADC or similar???
- let (v, carry1) = unsafe { $addfn(self, other) };
- let (v, carry2) = unsafe { $addfn(v, if carry {1} else {0}) };
- (carry1 || carry2, v)
- }
-
- fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) {
- // this cannot overflow, the output is between 0 and 2^nbits * (2^nbits - 1)
- let nbits = mem::size_of::<$ty>() * 8;
- let v = (self as $bigty) * (other as $bigty) + (carry as $bigty);
- ((v >> nbits) as $ty, v as $ty)
- }
-
- fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
- // this cannot overflow, the output is between 0 and 2^(2*nbits) - 1
- let nbits = mem::size_of::<$ty>() * 8;
- let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) +
- (carry as $bigty);
- ((v >> nbits) as $ty, v as $ty)
- }
-
- fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) {
- debug_assert!(borrow < other);
- // this cannot overflow, the dividend is between 0 and other * 2^nbits - 1
- let nbits = mem::size_of::<$ty>() * 8;
- let lhs = ((borrow as $bigty) << nbits) | (self as $bigty);
- let rhs = other as $bigty;
- ((lhs / rhs) as $ty, (lhs % rhs) as $ty)
- }
- }
- )*
- )
-}
-
-impl_full_ops! {
- u8: add(intrinsics::u8_add_with_overflow), mul/div(u16);
- u16: add(intrinsics::u16_add_with_overflow), mul/div(u32);
- u32: add(intrinsics::u32_add_with_overflow), mul/div(u64);
-// u64: add(intrinsics::u64_add_with_overflow), mul/div(u128); // see RFC #521 for enabling this.
-}
-
-/// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value
-/// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`.
-const SMALL_POW5: [(u64, usize); 3] = [
- (125, 3),
- (15625, 6),
- (1_220_703_125, 13),
-];
-
-macro_rules! define_bignum {
- ($name:ident: type=$ty:ty, n=$n:expr) => (
- /// Stack-allocated arbitrary-precision (up to certain limit) integer.
- ///
- /// This is backed by an fixed-size array of given type ("digit").
- /// While the array is not very large (normally some hundred bytes),
- /// copying it recklessly may result in the performance hit.
- /// Thus this is intentionally not `Copy`.
- ///
- /// All operations available to bignums panic in the case of over/underflows.
- /// The caller is responsible to use large enough bignum types.
- pub struct $name {
- /// One plus the offset to the maximum "digit" in use.
- /// This does not decrease, so be aware of the computation order.
- /// `base[size..]` should be zero.
- size: usize,
- /// Digits. `[a, b, c, ...]` represents `a + b*2^W + c*2^(2W) + ...`
- /// where `W` is the number of bits in the digit type.
- base: [$ty; $n]
- }
-
- impl $name {
- /// Makes a bignum from one digit.
- pub fn from_small(v: $ty) -> $name {
- let mut base = [0; $n];
- base[0] = v;
- $name { size: 1, base: base }
- }
-
- /// Makes a bignum from `u64` value.
- pub fn from_u64(mut v: u64) -> $name {
- use mem;
-
- let mut base = [0; $n];
- let mut sz = 0;
- while v > 0 {
- base[sz] = v as $ty;
- v >>= mem::size_of::<$ty>() * 8;
- sz += 1;
- }
- $name { size: sz, base: base }
- }
-
- /// Return the internal digits as a slice `[a, b, c, ...]` such that the numeric
- /// value is `a + b * 2^W + c * 2^(2W) + ...` where `W` is the number of bits in
- /// the digit type.
- pub fn digits(&self) -> &[$ty] {
- &self.base[..self.size]
- }
-
- /// Return the `i`-th bit where bit 0 is the least significant one.
- /// In other words, the bit with weight `2^i`.
- pub fn get_bit(&self, i: usize) -> u8 {
- use mem;
-
- let digitbits = mem::size_of::<$ty>() * 8;
- let d = i / digitbits;
- let b = i % digitbits;
- ((self.base[d] >> b) & 1) as u8
- }
-
- /// Returns true if the bignum is zero.
- pub fn is_zero(&self) -> bool {
- self.digits().iter().all(|&v| v == 0)
- }
-
- /// Returns the number of bits necessary to represent this value. Note that zero
- /// is considered to need 0 bits.
- pub fn bit_length(&self) -> usize {
- use mem;
-
- // Skip over the most significant digits which are zero.
- let digits = self.digits();
- let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
- let end = digits.len() - zeros;
- let nonzero = &digits[..end];
-
- if nonzero.is_empty() {
- // There are no non-zero digits, i.e. the number is zero.
- return 0;
- }
- // This could be optimized with leading_zeros() and bit shifts, but that's
- // probably not worth the hassle.
- let digitbits = mem::size_of::<$ty>()* 8;
- let mut i = nonzero.len() * digitbits - 1;
- while self.get_bit(i) == 0 {
- i -= 1;
- }
- i + 1
- }
-
- /// Adds `other` to itself and returns its own mutable reference.
- pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
- use cmp;
- use num::flt2dec::bignum::FullOps;
-
- let mut sz = cmp::max(self.size, other.size);
- let mut carry = false;
- for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) {
- let (c, v) = (*a).full_add(*b, carry);
- *a = v;
- carry = c;
- }
- if carry {
- self.base[sz] = 1;
- sz += 1;
- }
- self.size = sz;
- self
- }
-
- pub fn add_small(&mut self, other: $ty) -> &mut $name {
- use num::flt2dec::bignum::FullOps;
-
- let (mut carry, v) = self.base[0].full_add(other, false);
- self.base[0] = v;
- let mut i = 1;
- while carry {
- let (c, v) = self.base[i].full_add(0, carry);
- self.base[i] = v;
- carry = c;
- i += 1;
- }
- if i > self.size {
- self.size = i;
- }
- self
- }
-
- /// Subtracts `other` from itself and returns its own mutable reference.
- pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
- use cmp;
- use num::flt2dec::bignum::FullOps;
-
- let sz = cmp::max(self.size, other.size);
- let mut noborrow = true;
- for (a, b) in self.base[..sz].iter_mut().zip(&other.base[..sz]) {
- let (c, v) = (*a).full_add(!*b, noborrow);
- *a = v;
- noborrow = c;
- }
- assert!(noborrow);
- self.size = sz;
- self
- }
-
- /// Multiplies itself by a digit-sized `other` and returns its own
- /// mutable reference.
- pub fn mul_small(&mut self, other: $ty) -> &mut $name {
- use num::flt2dec::bignum::FullOps;
-
- let mut sz = self.size;
- let mut carry = 0;
- for a in &mut self.base[..sz] {
- let (c, v) = (*a).full_mul(other, carry);
- *a = v;
- carry = c;
- }
- if carry > 0 {
- self.base[sz] = carry;
- sz += 1;
- }
- self.size = sz;
- self
- }
-
- /// Multiplies itself by `2^bits` and returns its own mutable reference.
- pub fn mul_pow2(&mut self, bits: usize) -> &mut $name {
- use mem;
-
- let digitbits = mem::size_of::<$ty>() * 8;
- let digits = bits / digitbits;
- let bits = bits % digitbits;
-
- assert!(digits < $n);
- debug_assert!(self.base[$n-digits..].iter().all(|&v| v == 0));
- debug_assert!(bits == 0 || (self.base[$n-digits-1] >> (digitbits - bits)) == 0);
-
- // shift by `digits * digitbits` bits
- for i in (0..self.size).rev() {
- self.base[i+digits] = self.base[i];
- }
- for i in 0..digits {
- self.base[i] = 0;
- }
-
- // shift by `bits` bits
- let mut sz = self.size + digits;
- if bits > 0 {
- let last = sz;
- let overflow = self.base[last-1] >> (digitbits - bits);
- if overflow > 0 {
- self.base[last] = overflow;
- sz += 1;
- }
- for i in (digits+1..last).rev() {
- self.base[i] = (self.base[i] << bits) |
- (self.base[i-1] >> (digitbits - bits));
- }
- self.base[digits] <<= bits;
- // self.base[..digits] is zero, no need to shift
- }
-
- self.size = sz;
- self
- }
-
- /// Multiplies itself by `5^e` and returns its own mutable reference.
- pub fn mul_pow5(&mut self, mut e: usize) -> &mut $name {
- use mem;
- use num::flt2dec::bignum::SMALL_POW5;
-
- // There are exactly n trailing zeros on 2^n, and the only relevant digit sizes
- // are consecutive powers of two, so this is well suited index for the table.
- let table_index = mem::size_of::<$ty>().trailing_zeros() as usize;
- let (small_power, small_e) = SMALL_POW5[table_index];
- let small_power = small_power as $ty;
-
- // Multiply with the largest single-digit power as long as possible ...
- while e >= small_e {
- self.mul_small(small_power);
- e -= small_e;
- }
-
- // ... then finish off the remainder.
- let mut rest_power = 1;
- for _ in 0..e {
- rest_power *= 5;
- }
- self.mul_small(rest_power);
-
- self
- }
-
-
- /// Multiplies itself by a number described by `other[0] + other[1] * 2^W +
- /// other[2] * 2^(2W) + ...` (where `W` is the number of bits in the digit type)
- /// and returns its own mutable reference.
- pub fn mul_digits<'a>(&'a mut self, other: &[$ty]) -> &'a mut $name {
- // the internal routine. works best when aa.len() <= bb.len().
- fn mul_inner(ret: &mut [$ty; $n], aa: &[$ty], bb: &[$ty]) -> usize {
- use num::flt2dec::bignum::FullOps;
-
- let mut retsz = 0;
- for (i, &a) in aa.iter().enumerate() {
- if a == 0 { continue; }
- let mut sz = bb.len();
- let mut carry = 0;
- for (j, &b) in bb.iter().enumerate() {
- let (c, v) = a.full_mul_add(b, ret[i + j], carry);
- ret[i + j] = v;
- carry = c;
- }
- if carry > 0 {
- ret[i + sz] = carry;
- sz += 1;
- }
- if retsz < i + sz {
- retsz = i + sz;
- }
- }
- retsz
- }
-
- let mut ret = [0; $n];
- let retsz = if self.size < other.len() {
- mul_inner(&mut ret, &self.digits(), other)
- } else {
- mul_inner(&mut ret, other, &self.digits())
- };
- self.base = ret;
- self.size = retsz;
- self
- }
-
- /// Divides itself by a digit-sized `other` and returns its own
- /// mutable reference *and* the remainder.
- pub fn div_rem_small(&mut self, other: $ty) -> (&mut $name, $ty) {
- use num::flt2dec::bignum::FullOps;
-
- assert!(other > 0);
-
- let sz = self.size;
- let mut borrow = 0;
- for a in self.base[..sz].iter_mut().rev() {
- let (q, r) = (*a).full_div_rem(other, borrow);
- *a = q;
- borrow = r;
- }
- (self, borrow)
- }
-
- /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the
- /// remainder.
- pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) {
- use mem;
-
- // Stupid slow base-2 long division taken from
- // https://en.wikipedia.org/wiki/Division_algorithm
- // FIXME use a greater base ($ty) for the long division.
- assert!(!d.is_zero());
- let digitbits = mem::size_of::<$ty>() * 8;
- for digit in &mut q.base[..] {
- *digit = 0;
- }
- for digit in &mut r.base[..] {
- *digit = 0;
- }
- r.size = d.size;
- q.size = 1;
- let mut q_is_zero = true;
- let end = self.bit_length();
- for i in (0..end).rev() {
- r.mul_pow2(1);
- r.base[0] |= self.get_bit(i) as $ty;
- if &*r >= d {
- r.sub(d);
- // Set bit `i` of q to 1.
- let digit_idx = i / digitbits;
- let bit_idx = i % digitbits;
- if q_is_zero {
- q.size = digit_idx + 1;
- q_is_zero = false;
- }
- q.base[digit_idx] |= 1 << bit_idx;
- }
- }
- debug_assert!(q.base[q.size..].iter().all(|&d| d == 0));
- debug_assert!(r.base[r.size..].iter().all(|&d| d == 0));
- }
- }
-
- impl ::cmp::PartialEq for $name {
- fn eq(&self, other: &$name) -> bool { self.base[..] == other.base[..] }
- }
-
- impl ::cmp::Eq for $name {
- }
-
- impl ::cmp::PartialOrd for $name {
- fn partial_cmp(&self, other: &$name) -> ::option::Option<::cmp::Ordering> {
- ::option::Option::Some(self.cmp(other))
- }
- }
-
- impl ::cmp::Ord for $name {
- fn cmp(&self, other: &$name) -> ::cmp::Ordering {
- use cmp::max;
- let sz = max(self.size, other.size);
- let lhs = self.base[..sz].iter().cloned().rev();
- let rhs = other.base[..sz].iter().cloned().rev();
- lhs.cmp(rhs)
- }
- }
-
- impl ::clone::Clone for $name {
- fn clone(&self) -> $name {
- $name { size: self.size, base: self.base }
- }
- }
-
- impl ::fmt::Debug for $name {
- fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
- use mem;
-
- let sz = if self.size < 1 {1} else {self.size};
- let digitlen = mem::size_of::<$ty>() * 2;
-
- try!(write!(f, "{:#x}", self.base[sz-1]));
- for &v in self.base[..sz-1].iter().rev() {
- try!(write!(f, "_{:01$x}", v, digitlen));
- }
- ::result::Result::Ok(())
- }
- }
- )
-}
-
-/// The digit type for `Big32x40`.
-pub type Digit32 = u32;
-
-define_bignum!(Big32x40: type=Digit32, n=40);
-
-// this one is used for testing only.
-#[doc(hidden)]
-pub mod tests {
- use prelude::v1::*;
- define_bignum!(Big8x3: type=u8, n=3);
-}
pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded};
pub mod estimator;
-pub mod bignum;
pub mod decoder;
/// Digit-generation algorithms.
/// You probably would want `strategy::grisu::format_shortest` for this.
///
/// The `dec_bounds` is a tuple `(lo, hi)` such that the number is formatted
-/// as decimal only when `10^lo <= V < 10^hi`. Note that this is the *apparant* `V`
+/// as decimal only when `10^lo <= V < 10^hi`. Note that this is the *apparent* `V`
/// instead of the actual `v`! Thus any printed exponent in the exponential form
/// cannot be in this range, avoiding any confusion.
///
use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
use num::flt2dec::estimator::estimate_scaling_factor;
-use num::flt2dec::bignum::Digit32 as Digit;
-use num::flt2dec::bignum::Big32x40 as Big;
+use num::bignum::Digit32 as Digit;
+use num::bignum::Big32x40 as Big;
static POW10: [Digit; 10] = [1, 10, 100, 1000, 10000, 100000,
1000000, 10000000, 100000000, 1000000000];
use prelude::v1::*;
+use num::diy_float::Fp;
use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
-/// A custom 64-bit floating point type, representing `f * 2^e`.
-#[derive(Copy, Clone, Debug)]
-#[doc(hidden)]
-pub struct Fp {
- /// The integer mantissa.
- pub f: u64,
- /// The exponent in base 2.
- pub e: i16,
-}
-
-impl Fp {
- /// Returns a correctly rounded product of itself and `other`.
- pub fn mul(&self, other: &Fp) -> Fp {
- const MASK: u64 = 0xffffffff;
- let a = self.f >> 32;
- let b = self.f & MASK;
- let c = other.f >> 32;
- let d = other.f & MASK;
- let ac = a * c;
- let bc = b * c;
- let ad = a * d;
- let bd = b * d;
- let tmp = (bd >> 32) + (ad & MASK) + (bc & MASK) + (1 << 31) /* round */;
- let f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
- let e = self.e + other.e + 64;
- Fp { f: f, e: e }
- }
-
- /// Normalizes itself so that the resulting mantissa is at least `2^63`.
- pub fn normalize(&self) -> Fp {
- let mut f = self.f;
- let mut e = self.e;
- if f >> (64 - 32) == 0 { f <<= 32; e -= 32; }
- if f >> (64 - 16) == 0 { f <<= 16; e -= 16; }
- if f >> (64 - 8) == 0 { f <<= 8; e -= 8; }
- if f >> (64 - 4) == 0 { f <<= 4; e -= 4; }
- if f >> (64 - 2) == 0 { f <<= 2; e -= 2; }
- if f >> (64 - 1) == 0 { f <<= 1; e -= 1; }
- debug_assert!(f >= (1 >> 63));
- Fp { f: f, e: e }
- }
-
- /// Normalizes itself to have the shared exponent.
- /// It can only decrease the exponent (and thus increase the mantissa).
- pub fn normalize_to(&self, e: i16) -> Fp {
- let edelta = self.e - e;
- assert!(edelta >= 0);
- let edelta = edelta as usize;
- assert_eq!(self.f << edelta >> edelta, self.f);
- Fp { f: self.f << edelta, e: e }
- }
-}
// see the comments in `format_shortest_opt` for the rationale.
#[doc(hidden)] pub const ALPHA: i16 = -60;
// but scaling `max_ten_kappa << e` by 10 can result in overflow.
// thus we are being sloppy here and widen the error range by a factor of 10.
// this will increase the false negative rate, but only very, *very* slightly;
- // it can only matter noticably when the mantissa is bigger than 60 bits.
+ // it can only matter noticeably when the mantissa is bigger than 60 bits.
return possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e);
} else if ((exp as i32 - limit as i32) as usize) < buf.len() {
(exp - limit) as usize
use char::CharExt;
use cmp::{Eq, PartialOrd};
+use convert::From;
use fmt;
use intrinsics;
use marker::{Copy, Sized};
/// all standard arithmetic operations on the underlying value are
/// intended to have wrapping semantics.
#[stable(feature = "rust1", since = "1.0.0")]
-#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
+#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default)]
pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
pub mod wrapping;
+
+// All these modules are technically private and only exposed for libcoretest:
pub mod flt2dec;
pub mod dec2flt;
+pub mod bignum;
+pub mod diy_float;
/// Types that have a "zero" value.
///
#[unstable(feature = "zero_one",
reason = "unsure of placement, wants to use associated constants",
issue = "27739")]
-pub trait Zero {
+pub trait Zero: Sized {
/// The "zero" (usually, additive identity) for this type.
fn zero() -> Self;
}
#[unstable(feature = "zero_one",
reason = "unsure of placement, wants to use associated constants",
issue = "27739")]
-pub trait One {
+pub trait One: Sized {
/// The "one" (usually, multiplicative identity) for this type.
fn one() -> Self;
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_div(self, v: Self) -> Option<Self> {
- match v {
- 0 => None,
+ pub fn checked_div(self, other: Self) -> Option<Self> {
+ match other {
+ 0 => None,
-1 if self == Self::min_value()
- => None,
- v => Some(self / v),
+ => None,
+ other => Some(self / other),
}
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn checked_div(self, v: Self) -> Option<Self> {
- match v {
+ pub fn checked_div(self, other: Self) -> Option<Self> {
+ match other {
0 => None,
- v => Some(self / v),
+ other => Some(self / other),
}
}
// all valid digits are ascii, so we will just iterate over the utf8 bytes
// and cast them to chars. .to_digit() will safely return None for anything
- // other than a valid ascii digit for a the given radix, including the first-byte
+ // other than a valid ascii digit for the given radix, including the first-byte
// of multi-byte sequences
let src = src.as_bytes();
- match (src[0], &src[1..]) {
- (b'-', digits) if digits.is_empty() => Err(PIE { kind: Empty }),
- (b'-', digits) if is_signed_ty => {
- // The number is negative
- let mut result = T::from_u32(0);
- for &c in digits {
- let x = match (c as char).to_digit(radix) {
- Some(x) => x,
- None => return Err(PIE { kind: InvalidDigit }),
- };
- result = match result.checked_mul(radix) {
- Some(result) => result,
- None => return Err(PIE { kind: Underflow }),
- };
- result = match result.checked_sub(x) {
- Some(result) => result,
- None => return Err(PIE { kind: Underflow }),
- };
- }
- Ok(result)
- },
- (c, digits) => {
- // The number is signed
- let mut result = match (c as char).to_digit(radix) {
- Some(x) => T::from_u32(x),
+ let (is_positive, digits) = match src[0] {
+ b'+' => (true, &src[1..]),
+ b'-' if is_signed_ty => (false, &src[1..]),
+ _ => (true, src)
+ };
+
+ if digits.is_empty() {
+ return Err(PIE { kind: Empty });
+ }
+
+ let mut result = T::from_u32(0);
+ if is_positive {
+ // The number is positive
+ for &c in digits {
+ let x = match (c as char).to_digit(radix) {
+ Some(x) => x,
None => return Err(PIE { kind: InvalidDigit }),
};
- for &c in digits {
- let x = match (c as char).to_digit(radix) {
- Some(x) => x,
- None => return Err(PIE { kind: InvalidDigit }),
- };
- result = match result.checked_mul(radix) {
- Some(result) => result,
- None => return Err(PIE { kind: Overflow }),
- };
- result = match result.checked_add(x) {
- Some(result) => result,
- None => return Err(PIE { kind: Overflow }),
- };
- }
- Ok(result)
+ result = match result.checked_mul(radix) {
+ Some(result) => result,
+ None => return Err(PIE { kind: Overflow }),
+ };
+ result = match result.checked_add(x) {
+ Some(result) => result,
+ None => return Err(PIE { kind: Overflow }),
+ };
+ }
+ } else {
+ // The number is negative
+ for &c in digits {
+ let x = match (c as char).to_digit(radix) {
+ Some(x) => x,
+ None => return Err(PIE { kind: InvalidDigit }),
+ };
+ result = match result.checked_mul(radix) {
+ Some(result) => result,
+ None => return Err(PIE { kind: Underflow }),
+ };
+ result = match result.checked_sub(x) {
+ Some(result) => result,
+ None => return Err(PIE { kind: Underflow }),
+ };
}
}
+ Ok(result)
}
/// An error which can be returned when parsing an integer.
}
pub use num::dec2flt::ParseFloatError;
+
+// Conversion traits for primitive integer types
+// Conversions T -> T are covered by a blanket impl and therefore excluded
+// Some conversions from and to usize/isize are not implemented due to portability concerns
+macro_rules! impl_from {
+ ($Small: ty, $Large: ty) => {
+ #[stable(feature = "lossless_int_conv", since = "1.5.0")]
+ impl From<$Small> for $Large {
+ #[stable(feature = "lossless_int_conv", since = "1.5.0")]
+ #[inline]
+ fn from(small: $Small) -> $Large {
+ small as $Large
+ }
+ }
+ }
+}
+
+// Unsigned -> Unsigned
+impl_from! { u8, u16 }
+impl_from! { u8, u32 }
+impl_from! { u8, u64 }
+impl_from! { u8, usize }
+impl_from! { u16, u32 }
+impl_from! { u16, u64 }
+impl_from! { u32, u64 }
+
+// Signed -> Signed
+impl_from! { i8, i16 }
+impl_from! { i8, i32 }
+impl_from! { i8, i64 }
+impl_from! { i8, isize }
+impl_from! { i16, i32 }
+impl_from! { i16, i64 }
+impl_from! { i32, i64 }
+
+// Unsigned -> Signed
+impl_from! { u8, i16 }
+impl_from! { u8, i32 }
+impl_from! { u8, i64 }
+impl_from! { u16, i32 }
+impl_from! { u16, i64 }
+impl_from! { u32, i64 }
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
- /// The `drop` method, called when the value goes out of scope.
+ /// A method called when the value goes out of scope.
#[stable(feature = "rust1", since = "1.0.0")]
fn drop(&mut self);
}
shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
+/// The `AddAssign` trait is used to specify the functionality of `+=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `AddAssign`. When `Foo += Foo` happens, it ends up
+/// calling `add_assign`, and therefore, `main` prints `Adding!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::AddAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl AddAssign for Foo {
+/// fn add_assign(&mut self, _rhs: Foo) {
+/// println!("Adding!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo += Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "add_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait AddAssign<Rhs=Self> {
+ /// The method for the `+=` operator
+ fn add_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! add_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl AddAssign for $t {
+ #[inline]
+ fn add_assign(&mut self, other: $t) { *self += other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+add_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+
+/// The `SubAssign` trait is used to specify the functionality of `-=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `SubAssign`. When `Foo -= Foo` happens, it ends up
+/// calling `sub_assign`, and therefore, `main` prints `Subtracting!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::SubAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl SubAssign for Foo {
+/// fn sub_assign(&mut self, _rhs: Foo) {
+/// println!("Subtracting!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo -= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "sub_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait SubAssign<Rhs=Self> {
+ /// The method for the `-=` operator
+ fn sub_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! sub_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl SubAssign for $t {
+ #[inline]
+ fn sub_assign(&mut self, other: $t) { *self -= other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+sub_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+
+/// The `MulAssign` trait is used to specify the functionality of `*=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `MulAssign`. When `Foo *= Foo` happens, it ends up
+/// calling `mul_assign`, and therefore, `main` prints `Multiplying!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::MulAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl MulAssign for Foo {
+/// fn mul_assign(&mut self, _rhs: Foo) {
+/// println!("Multiplying!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo *= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "mul_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait MulAssign<Rhs=Self> {
+ /// The method for the `*=` operator
+ fn mul_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! mul_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl MulAssign for $t {
+ #[inline]
+ fn mul_assign(&mut self, other: $t) { *self *= other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+mul_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+
+/// The `DivAssign` trait is used to specify the functionality of `/=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `DivAssign`. When `Foo /= Foo` happens, it ends up
+/// calling `div_assign`, and therefore, `main` prints `Dividing!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::DivAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl DivAssign for Foo {
+/// fn div_assign(&mut self, _rhs: Foo) {
+/// println!("Dividing!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo /= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "div_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait DivAssign<Rhs=Self> {
+ /// The method for the `/=` operator
+ fn div_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! div_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl DivAssign for $t {
+ #[inline]
+ fn div_assign(&mut self, other: $t) { *self /= other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+div_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+
+/// The `RemAssign` trait is used to specify the functionality of `%=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `RemAssign`. When `Foo %= Foo` happens, it ends up
+/// calling `rem_assign`, and therefore, `main` prints `Remainder-ing!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::RemAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl RemAssign for Foo {
+/// fn rem_assign(&mut self, _rhs: Foo) {
+/// println!("Remainder-ing!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo %= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "rem_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait RemAssign<Rhs=Self> {
+ /// The method for the `%=` operator
+ fn rem_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! rem_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl RemAssign for $t {
+ #[inline]
+ fn rem_assign(&mut self, other: $t) { *self %= other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+rem_assign_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 }
+
+/// The `BitAndAssign` trait is used to specify the functionality of `&=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `BitAndAssign`. When `Foo &= Foo` happens, it ends up
+/// calling `bitand_assign`, and therefore, `main` prints `Bitwise And-ing!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::BitAndAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl BitAndAssign for Foo {
+/// fn bitand_assign(&mut self, _rhs: Foo) {
+/// println!("Bitwise And-ing!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo &= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "bitand_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait BitAndAssign<Rhs=Self> {
+ /// The method for the `&` operator
+ fn bitand_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! bitand_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl BitAndAssign for $t {
+ #[inline]
+ fn bitand_assign(&mut self, other: $t) { *self &= other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+bitand_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
+
+/// The `BitOrAssign` trait is used to specify the functionality of `|=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `BitOrAssign`. When `Foo |= Foo` happens, it ends up
+/// calling `bitor_assign`, and therefore, `main` prints `Bitwise Or-ing!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::BitOrAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl BitOrAssign for Foo {
+/// fn bitor_assign(&mut self, _rhs: Foo) {
+/// println!("Bitwise Or-ing!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo |= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "bitor_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait BitOrAssign<Rhs=Self> {
+ /// The method for the `|=` operator
+ fn bitor_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! bitor_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl BitOrAssign for $t {
+ #[inline]
+ fn bitor_assign(&mut self, other: $t) { *self |= other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+bitor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
+
+/// The `BitXorAssign` trait is used to specify the functionality of `^=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `BitXorAssign`. When `Foo ^= Foo` happens, it ends up
+/// calling `bitxor_assign`, and therefore, `main` prints `Bitwise Xor-ing!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::BitXorAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl BitXorAssign for Foo {
+/// fn bitxor_assign(&mut self, _rhs: Foo) {
+/// println!("Bitwise Xor-ing!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo ^= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "bitxor_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait BitXorAssign<Rhs=Self> {
+ /// The method for the `^=` operator
+ fn bitxor_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! bitxor_assign_impl {
+ ($($t:ty)+) => ($(
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl BitXorAssign for $t {
+ #[inline]
+ fn bitxor_assign(&mut self, other: $t) { *self ^= other }
+ }
+ )+)
+}
+
+#[cfg(not(stage0))]
+bitxor_assign_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
+
+/// The `ShlAssign` trait is used to specify the functionality of `<<=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `ShlAssign`. When `Foo <<= Foo` happens, it ends up
+/// calling `shl_assign`, and therefore, `main` prints `Shifting left!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::ShlAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl ShlAssign<Foo> for Foo {
+/// fn shl_assign(&mut self, _rhs: Foo) {
+/// println!("Shifting left!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo <<= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "shl_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait ShlAssign<Rhs> {
+ /// The method for the `<<=` operator
+ fn shl_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! shl_assign_impl {
+ ($t:ty, $f:ty) => (
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl ShlAssign<$f> for $t {
+ #[inline]
+ fn shl_assign(&mut self, other: $f) {
+ *self <<= other
+ }
+ }
+ )
+}
+
+#[cfg(not(stage0))]
+macro_rules! shl_assign_impl_all {
+ ($($t:ty)*) => ($(
+ shl_assign_impl! { $t, u8 }
+ shl_assign_impl! { $t, u16 }
+ shl_assign_impl! { $t, u32 }
+ shl_assign_impl! { $t, u64 }
+ shl_assign_impl! { $t, usize }
+
+ shl_assign_impl! { $t, i8 }
+ shl_assign_impl! { $t, i16 }
+ shl_assign_impl! { $t, i32 }
+ shl_assign_impl! { $t, i64 }
+ shl_assign_impl! { $t, isize }
+ )*)
+}
+
+#[cfg(not(stage0))]
+shl_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
+
+/// The `ShrAssign` trait is used to specify the functionality of `>>=`.
+///
+/// # Examples
+///
+/// A trivial implementation of `ShrAssign`. When `Foo >>= Foo` happens, it ends up
+/// calling `shr_assign`, and therefore, `main` prints `Shifting right!`.
+///
+/// ```
+/// #![feature(augmented_assignments)]
+/// #![feature(op_assign_traits)]
+///
+/// use std::ops::ShrAssign;
+///
+/// #[derive(Copy, Clone)]
+/// struct Foo;
+///
+/// impl ShrAssign<Foo> for Foo {
+/// fn shr_assign(&mut self, _rhs: Foo) {
+/// println!("Shifting right!");
+/// }
+/// }
+///
+/// fn main() {
+/// let mut foo = Foo;
+/// foo >>= Foo;
+/// }
+/// ```
+#[cfg(not(stage0))]
+#[lang = "shr_assign"]
+#[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+pub trait ShrAssign<Rhs=Self> {
+ /// The method for the `>>=` operator
+ fn shr_assign(&mut self, Rhs);
+}
+
+#[cfg(not(stage0))]
+macro_rules! shr_assign_impl {
+ ($t:ty, $f:ty) => (
+ #[unstable(feature = "op_assign_traits", reason = "recently added", issue = "28235")]
+ impl ShrAssign<$f> for $t {
+ #[inline]
+ fn shr_assign(&mut self, other: $f) {
+ *self >>= other
+ }
+ }
+ )
+}
+
+#[cfg(not(stage0))]
+macro_rules! shr_assign_impl_all {
+ ($($t:ty)*) => ($(
+ shr_assign_impl! { $t, u8 }
+ shr_assign_impl! { $t, u16 }
+ shr_assign_impl! { $t, u32 }
+ shr_assign_impl! { $t, u64 }
+ shr_assign_impl! { $t, usize }
+
+ shr_assign_impl! { $t, i8 }
+ shr_assign_impl! { $t, i16 }
+ shr_assign_impl! { $t, i32 }
+ shr_assign_impl! { $t, i64 }
+ shr_assign_impl! { $t, isize }
+ )*)
+}
+
+#[cfg(not(stage0))]
+shr_assign_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
+
/// The `Index` trait is used to specify the functionality of indexing operations
/// like `arr[idx]` when used in an immutable context.
///
/// impl<T> Deref for DerefExample<T> {
/// type Target = T;
///
-/// fn deref<'a>(&'a self) -> &'a T {
+/// fn deref(&self) -> &T {
/// &self.value
/// }
/// }
reason = "waiting for mut conventions",
issue = "27776")]
#[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")]
+ #[allow(deprecated)]
pub fn as_mut_slice(&mut self) -> &mut [T] {
match *self {
Some(ref mut x) => {
/// ```
/// let mut x = Some(4);
/// match x.iter_mut().next() {
- /// Some(&mut ref mut v) => *v = 42,
+ /// Some(v) => *v = 42,
/// None => {},
/// }
/// assert_eq!(x, Some(42));
#[unstable(feature = "as_slice", reason = "unsure of the utility here",
issue = "27776")]
#[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")]
+ #[allow(deprecated)]
pub fn as_slice(&self) -> &[T] {
match *self {
Some(ref x) => slice::ref_slice(x),
}
impl<'a, T: Clone> Option<&'a T> {
- /// Maps an Option<&T> to an Option<T> by cloning the contents of the Option.
+ /// Maps an `Option<&T>` to an `Option<T>` by cloning the contents of the
+ /// option.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn cloned(self) -> Option<T> {
self.map(|t| t.clone())
use clone::Clone;
use intrinsics;
-use ops::Deref;
+use ops::{CoerceUnsized, Deref};
use fmt;
use hash;
use option::Option::{self, Some, None};
-use marker::{PhantomData, Send, Sized, Sync};
+use marker::{Copy, PhantomData, Send, Sized, Sync, Unsize};
use mem;
use nonzero::NonZero;
pub const fn null_mut<T>() -> *mut T { 0 as *mut T }
/// Swaps the values at two mutable locations of the same type, without
-/// deinitialising either. They may overlap, unlike `mem::swap` which is
+/// deinitializing either. They may overlap, unlike `mem::swap` which is
/// otherwise equivalent.
///
/// # Safety
///
/// # Safety
///
-/// Beyond accepting a raw pointer, this operation is unsafe because it does
-/// not drop the contents of `dst`. This could leak allocations or resources,
-/// so care must be taken not to overwrite an object that should be dropped.
+/// This operation is marked unsafe because it accepts a raw pointer.
+///
+/// It does not drop the contents of `dst`. This is safe, but it could leak
+/// allocations or resources, so care must be taken not to overwrite an object
+/// that should be dropped.
///
/// This is appropriate for initializing uninitialized memory, or overwriting
/// memory that has previously been `read` from.
/// # Safety
///
/// The offset must be in-bounds of the object, or one-byte-past-the-end.
- /// Otherwise `offset` invokes Undefined Behaviour, regardless of whether
+ /// Otherwise `offset` invokes Undefined Behavior, regardless of whether
/// the pointer is used.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
#[unstable(feature = "unique", issue = "27730")]
unsafe impl<T: Sync + ?Sized> Sync for Unique<T> { }
+#[cfg(stage0)]
+macro_rules! unique_new {
+ () => (
+ /// Creates a new `Unique`.
+ pub unsafe fn new(ptr: *mut T) -> Unique<T> {
+ Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
+ }
+ )
+}
+#[cfg(not(stage0))]
+macro_rules! unique_new {
+ () => (
+ /// Creates a new `Unique`.
+ pub const unsafe fn new(ptr: *mut T) -> Unique<T> {
+ Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
+ }
+ )
+}
+
#[unstable(feature = "unique", issue = "27730")]
impl<T: ?Sized> Unique<T> {
- /// Creates a new `Unique`.
- pub unsafe fn new(ptr: *mut T) -> Unique<T> {
- Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
- }
+ unique_new!{}
/// Dereferences the content.
pub unsafe fn get(&self) -> &T {
fmt::Pointer::fmt(&*self.pointer, f)
}
}
+
+/// A wrapper around a raw `*mut T` that indicates that the possessor
+/// of this wrapper has shared ownership of the referent. Useful for
+/// building abstractions like `Rc<T>` or `Arc<T>`, which internally
+/// use raw pointers to manage the memory that they own.
+#[unstable(feature = "shared", reason = "needs an RFC to flesh out design",
+ issue = "27730")]
+pub struct Shared<T: ?Sized> {
+ pointer: NonZero<*const T>,
+ // NOTE: this marker has no consequences for variance, but is necessary
+ // for dropck to understand that we logically own a `T`.
+ //
+ // For details, see:
+ // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
+ _marker: PhantomData<T>,
+}
+
+/// `Shared` pointers are not `Send` because the data they reference may be aliased.
+// NB: This impl is unnecessary, but should provide better error messages.
+#[unstable(feature = "shared", issue = "27730")]
+impl<T: ?Sized> !Send for Shared<T> { }
+
+/// `Shared` pointers are not `Sync` because the data they reference may be aliased.
+// NB: This impl is unnecessary, but should provide better error messages.
+#[unstable(feature = "shared", issue = "27730")]
+impl<T: ?Sized> !Sync for Shared<T> { }
+
+#[unstable(feature = "shared", issue = "27730")]
+impl<T: ?Sized> Shared<T> {
+ /// Creates a new `Shared`.
+ pub unsafe fn new(ptr: *mut T) -> Self {
+ Shared { pointer: NonZero::new(ptr), _marker: PhantomData }
+ }
+}
+
+#[unstable(feature = "shared", issue = "27730")]
+impl<T: ?Sized> Clone for Shared<T> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+#[unstable(feature = "shared", issue = "27730")]
+impl<T: ?Sized> Copy for Shared<T> { }
+
+#[cfg(not(stage0))] // remove cfg after new snapshot
+#[unstable(feature = "shared", issue = "27730")]
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<Shared<U>> for Shared<T> where T: Unsize<U> { }
+
+#[unstable(feature = "shared", issue = "27730")]
+impl<T: ?Sized> Deref for Shared<T> {
+ type Target = *mut T;
+
+ #[inline]
+ fn deref(&self) -> &*mut T {
+ unsafe { mem::transmute(&*self.pointer) }
+ }
+}
+
+#[unstable(feature = "shared", issue = "27730")]
+impl<T> fmt::Pointer for Shared<T> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Pointer::fmt(&*self.pointer, f)
+ }
+}
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
-/// behaviour.
+/// behavior.
///
/// # Examples
///
#[unstable(feature = "as_slice", reason = "unsure of the utility here",
issue = "27776")]
#[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")]
+ #[allow(deprecated)]
pub fn as_slice(&self) -> &[T] {
match *self {
Ok(ref x) => slice::ref_slice(x),
reason = "waiting for mut conventions",
issue = "27776")]
#[deprecated(since = "1.4.0", reason = "niche API, unclear of usefulness")]
+ #[allow(deprecated)]
pub fn as_mut_slice(&mut self) -> &mut [T] {
match *self {
Ok(ref mut x) => slice::mut_ref_slice(x),
/// ```
/// let mut x: Result<u32, &str> = Ok(7);
/// match x.iter_mut().next() {
- /// Some(&mut ref mut x) => *x = 40,
+ /// Some(v) => *v = 40,
/// None => {},
/// }
/// assert_eq!(x, Ok(40));
fn default() -> &'a [T] { &[] }
}
+#[stable(feature = "mut_slice_default", since = "1.5.0")]
+impl<'a, T> Default for &'a mut [T] {
+ fn default() -> &'a mut [T] { &mut [] }
+}
+
//
// Iterators
//
// Free functions
//
-/// Converts a pointer to A into a slice of length 1 (without copying).
+/// Converts a reference to A into a slice of length 1 (without copying).
#[unstable(feature = "ref_slice", issue = "27774")]
+#[deprecated(since = "1.5.0", reason = "unclear whether belongs in libstd")]
pub fn ref_slice<A>(s: &A) -> &[A] {
unsafe {
from_raw_parts(s, 1)
}
}
-/// Converts a pointer to A into a slice of length 1 (without copying).
+/// Converts a reference to A into a slice of length 1 (without copying).
#[unstable(feature = "ref_slice", issue = "27774")]
+#[deprecated(since = "1.5.0", reason = "unclear whether belongs in libstd")]
pub fn mut_ref_slice<A>(s: &mut A) -> &mut [A] {
unsafe {
from_raw_parts_mut(s, 1)
///
/// The `len` argument is the number of **elements**, not the number of bytes.
///
-/// # Unsafety
+/// # Safety
///
/// This function is unsafe as there is no guarantee that the given pointer is
/// valid for `len` elements, nor whether the lifetime inferred is a suitable
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Ord for [T] {
fn cmp(&self, other: &[T]) -> Ordering {
- self.iter().cmp(other.iter())
+ let l = cmp::min(self.len(), other.len());
+
+ // Slice to the loop iteration range to enable bound check
+ // elimination in the compiler
+ let lhs = &self[..l];
+ let rhs = &other[..l];
+
+ for i in 0..l {
+ match lhs[i].cmp(&rhs[i]) {
+ Ordering::Equal => (),
+ non_eq => return non_eq,
+ }
+ }
+
+ self.len().cmp(&other.len())
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd> PartialOrd for [T] {
- #[inline]
fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
- self.iter().partial_cmp(other.iter())
- }
- #[inline]
- fn lt(&self, other: &[T]) -> bool {
- self.iter().lt(other.iter())
- }
- #[inline]
- fn le(&self, other: &[T]) -> bool {
- self.iter().le(other.iter())
- }
- #[inline]
- fn ge(&self, other: &[T]) -> bool {
- self.iter().ge(other.iter())
- }
- #[inline]
- fn gt(&self, other: &[T]) -> bool {
- self.iter().gt(other.iter())
+ let l = cmp::min(self.len(), other.len());
+
+ // Slice to the loop iteration range to enable bound check
+ // elimination in the compiler
+ let lhs = &self[..l];
+ let rhs = &other[..l];
+
+ for i in 0..l {
+ match lhs[i].partial_cmp(&rhs[i]) {
+ Some(Ordering::Equal) => (),
+ non_eq => return non_eq,
+ }
+ }
+
+ self.len().partial_cmp(&other.len())
}
}
/// If parsing succeeds, return the value inside `Ok`, otherwise
/// when the string is ill-formatted return an error specific to the
/// inside `Err`. The error type is specific to implementation of the trait.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`:
+ ///
+ /// [ithirtytwo]: ../primitive.i32.html
+ ///
+ /// ```
+ /// use std::str::FromStr;
+ ///
+ /// let s = "5";
+ /// let x = i32::from_str(s).unwrap();
+ ///
+ /// assert_eq!(5, x);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
Section: Creating a string
*/
-/// Errors which can occur when attempting to interpret a byte slice as a `str`.
+/// Errors which can occur when attempting to interpret a sequence of `u8`
+/// as a string.
+///
+/// As such, the `from_utf8` family of functions and methods for both `String`s
+/// and `&str`s make use of this error, for example.
#[derive(Copy, Eq, PartialEq, Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Utf8Error {
/// Returns the index in the given string up to which valid UTF-8 was
/// verified.
///
- /// Starting at the index provided, but not necessarily at it precisely, an
- /// invalid UTF-8 encoding sequence was found.
- #[unstable(feature = "utf8_error", reason = "method just added",
- issue = "27734")]
+ /// It is the maximum index such that `from_utf8(input[..index])`
+ /// would return `Some(_)`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// #![feature(utf8_error)]
+ ///
+ /// use std::str;
+ ///
+ /// // some invalid bytes, in a vector
+ /// let sparkle_heart = vec![0, 159, 146, 150];
+ ///
+ /// // std::str::from_utf8 returns a Utf8Error
+ /// let error = str::from_utf8(&sparkle_heart).unwrap_err();
+ ///
+ /// // the first byte is invalid here
+ /// assert_eq!(1, error.valid_up_to());
+ /// ```
+ #[stable(feature = "utf8_error", since = "1.5.0")]
pub fn valid_up_to(&self) -> usize { self.valid_up_to }
}
-/// Converts a slice of bytes to a string slice without performing any
-/// allocations.
+/// Converts a slice of bytes to a string slice.
///
-/// Once the slice has been validated as UTF-8, it is transmuted in-place and
-/// returned as a '&str' instead of a '&[u8]'
+/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`)
+/// is made of bytes, so this function converts between the two. Not all byte
+/// slices are valid string slices, however: `&str` requires that it is valid
+/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and
+/// then does the conversion.
+///
+/// If you are sure that the byte slice is valid UTF-8, and you don't want to
+/// incur the overhead of the validity check, there is an unsafe version of
+/// this function, [`from_utf8_unchecked()`][fromutf8], which has the same
+/// behavior but skips the check.
+///
+/// [fromutf8]: fn.from_utf8.html
+///
+/// If you need a `String` instead of a `&str`, consider
+/// [`String::from_utf8()`][string].
+///
+/// [string]: ../string/struct.String.html#method.from_utf8
+///
+/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of
+/// it, this function is one way to have a stack-allocated string. There is
+/// an example of this in the examples section below.
///
/// # Failure
///
/// Returns `Err` if the slice is not UTF-8 with a description as to why the
/// provided slice is not UTF-8.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // some bytes, in a vector
+/// let sparkle_heart = vec![240, 159, 146, 150];
+///
+/// // We know these bytes are valid, so just use `unwrap()`.
+/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap();
+///
+/// assert_eq!("💖", sparkle_heart);
+/// ```
+///
+/// Incorrect bytes:
+///
+/// ```
+/// use std::str;
+///
+/// // some invalid bytes, in a vector
+/// let sparkle_heart = vec![0, 159, 146, 150];
+///
+/// assert!(str::from_utf8(&sparkle_heart).is_err());
+/// ```
+///
+/// See the docs for [`Utf8Error`][error] for more details on the kinds of
+/// errors that can be returned.
+///
+/// [error]: struct.Utf8Error.html
+///
+/// A "stack allocated string":
+///
+/// ```
+/// use std::str;
+///
+/// // some bytes, in a stack-allocated array
+/// let sparkle_heart = [240, 159, 146, 150];
+///
+/// // We know these bytes are valid, so just use `unwrap()`.
+/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap();
+///
+/// assert_eq!("💖", sparkle_heart);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
try!(run_utf8_validation_iterator(&mut v.iter()));
/// Converts a slice of bytes to a string slice without checking
/// that the string contains valid UTF-8.
+///
+/// See the safe version, [`from_utf8()`][fromutf8], for more.
+///
+/// [fromutf8]: fn.from_utf8.html
+///
+/// # Safety
+///
+/// This function is unsafe because it does not check that the bytes passed to
+/// it are valid UTF-8. If this constraint is violated, undefined behavior
+/// results, as the rest of Rust assumes that `&str`s are valid UTF-8.
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// use std::str;
+///
+/// // some bytes, in a vector
+/// let sparkle_heart = vec![240, 159, 146, 150];
+///
+/// let sparkle_heart = unsafe {
+/// str::from_utf8_unchecked(&sparkle_heart)
+/// };
+///
+/// assert_eq!("💖", sparkle_heart);
+/// ```
#[inline(always)]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
}
/// This macro generates two public iterator structs
-/// wrapping an private internal one that makes use of the `Pattern` API.
+/// wrapping a private internal one that makes use of the `Pattern` API.
///
/// For all patterns `P: Pattern<'a>` the following items will be
/// generated (generics omitted):
impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> {
#[inline]
- fn next(&mut self) -> Option<(usize, usize)> {
- self.0.next_match()
+ fn next(&mut self) -> Option<(usize, &'a str)> {
+ self.0.next_match().map(|(start, end)| unsafe {
+ (start, self.0.haystack().slice_unchecked(start, end))
+ })
}
#[inline]
- fn next_back(&mut self) -> Option<(usize, usize)>
+ fn next_back(&mut self) -> Option<(usize, &'a str)>
where P::Searcher: ReverseSearcher<'a>
{
- self.0.next_match_back()
+ self.0.next_match_back().map(|(start, end)| unsafe {
+ (start, self.0.haystack().slice_unchecked(start, end))
+ })
}
}
/// Created with the method `.rmatch_indices()`.
struct RMatchIndices;
stability:
- #[unstable(feature = "str_match_indices",
- reason = "type may be removed or have its iterator impl changed",
- issue = "27743")]
+ #[stable(feature = "str_match_indices", since = "1.5.0")]
internal:
- MatchIndicesInternal yielding ((usize, usize));
+ MatchIndicesInternal yielding ((usize, &'a str));
delegate double ended;
}
#[allow(deprecated)]
pub struct LinesAny<'a>(Lines<'a>);
-/// A nameable, clonable fn type
+/// A nameable, cloneable fn type
#[derive(Clone)]
struct LinesAnyMap;
}
}
+// Send is implicitly implemented for AtomicBool.
unsafe impl Sync for AtomicBool {}
/// A signed integer type which can be safely shared between threads.
}
}
+// Send is implicitly implemented for AtomicIsize.
unsafe impl Sync for AtomicIsize {}
/// An unsigned integer type which can be safely shared between threads.
}
}
+// Send is implicitly implemented for AtomicUsize.
unsafe impl Sync for AtomicUsize {}
/// A raw pointer type which can be safely shared between threads.
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Copy, Clone)]
pub enum Ordering {
- /// No ordering constraints, only atomic operations.
+ /// No ordering constraints, only atomic operations. Corresponds to LLVM's
+ /// `Monotonic` ordering.
#[stable(feature = "rust1", since = "1.0.0")]
Relaxed,
/// When coupled with a store, all previous writes become visible
assert_eq!(unsafe { &mut *cell.get() }, comp);
}
-// FIXME(#25351) needs deeply nested coercions of DST structs.
-// #[test]
-// fn refcell_unsized() {
-// let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]);
-// {
-// let b = &mut *cell.borrow_mut();
-// b[0] = 4;
-// b[2] = 5;
-// }
-// let comp: &mut [i32] = &mut [4, 2, 5];
-// assert_eq!(&*cell.borrow(), comp);
-// }
+#[test]
+fn refcell_unsized() {
+ let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]);
+ {
+ let b = &mut *cell.borrow_mut();
+ b[0] = 4;
+ b[2] = 5;
+ }
+ let comp: &mut [i32] = &mut [4, 2, 5];
+ assert_eq!(&*cell.borrow(), comp);
+}
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
#[test]
fn test_borrowed_clone() {
let x = 5;
- let y: &int = &x;
- let z: &int = (&y).clone();
+ let y: &i32 = &x;
+ let z: &i32 = (&y).clone();
assert_eq!(*z, 5);
}
b.clone_from(&a);
assert_eq!(*b, 5);
}
-
-#[test]
-fn test_extern_fn_clone() {
- trait Empty {}
- impl Empty for int {}
-
- fn test_fn_a() -> f64 { 1.0 }
- fn test_fn_b<T: Empty>(x: T) -> T { x }
- fn test_fn_c(_: int, _: f64, _: int, _: int, _: int) {}
-
- let _ = test_fn_a.clone();
- let _ = test_fn_b::<int>.clone();
- let _ = test_fn_c.clone();
-}
assert!("1" == format!("{:.0}", 1.0f64));
assert!("9" == format!("{:.0}", 9.4f64));
assert!("10" == format!("{:.0}", 9.9f64));
- assert!("9.9" == format!("{:.1}", 9.85f64));
+ assert!("9.8" == format!("{:.1}", 9.849f64));
+ assert!("9.9" == format!("{:.1}", 9.851f64));
+ assert!("1" == format!("{:.0}", 0.5f64));
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-mod num;
mod builders;
+mod float;
+mod num;
#[test]
fn test_format_flags() {
#[test]
fn test_typeid_sized_types() {
- struct X; struct Y(uint);
+ struct X; struct Y(u32);
assert_eq!(TypeId::of::<X>(), TypeId::of::<X>());
assert_eq!(TypeId::of::<Y>(), TypeId::of::<Y>());
#![feature(const_fn)]
#![feature(core)]
#![feature(core_float)]
+#![feature(core_private_bignum)]
+#![feature(core_private_diy_float)]
#![feature(dec2flt)]
#![feature(decode_utf16)]
#![feature(fixed_size_array)]
mod atomic;
mod cell;
mod char;
+mod clone;
mod cmp;
mod fmt;
mod hash;
+mod intrinsics;
mod iter;
mod mem;
mod nonzero;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::prelude::v1::*;
+use core::num::bignum::tests::Big8x3 as Big;
+
+#[test]
+#[should_panic]
+fn test_from_u64_overflow() {
+ Big::from_u64(0x1000000);
+}
+
+#[test]
+fn test_add() {
+ assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7));
+ assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3));
+ assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3));
+ assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001));
+ assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665));
+ assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665));
+}
+
+#[test]
+#[should_panic]
+fn test_add_overflow_1() {
+ Big::from_small(1).add(&Big::from_u64(0xffffff));
+}
+
+#[test]
+#[should_panic]
+fn test_add_overflow_2() {
+ Big::from_u64(0xffffff).add(&Big::from_small(1));
+}
+
+#[test]
+fn test_add_small() {
+ assert_eq!(*Big::from_small(3).add_small(4), Big::from_small(7));
+ assert_eq!(*Big::from_small(3).add_small(0), Big::from_small(3));
+ assert_eq!(*Big::from_small(0).add_small(3), Big::from_small(3));
+ assert_eq!(*Big::from_small(7).add_small(250), Big::from_u64(257));
+ assert_eq!(*Big::from_u64(0x7fff).add_small(1), Big::from_u64(0x8000));
+ assert_eq!(*Big::from_u64(0x2ffe).add_small(0x35), Big::from_u64(0x3033));
+ assert_eq!(*Big::from_small(0xdc).add_small(0x89), Big::from_u64(0x165));
+}
+
+#[test]
+#[should_panic]
+fn test_add_small_overflow() {
+ Big::from_u64(0xffffff).add_small(1);
+}
+
+#[test]
+fn test_sub() {
+ assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1));
+ assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0));
+}
+
+#[test]
+#[should_panic]
+fn test_sub_underflow_1() {
+ Big::from_u64(0x10665).sub(&Big::from_u64(0x10666));
+}
+
+#[test]
+#[should_panic]
+fn test_sub_underflow_2() {
+ Big::from_small(0).sub(&Big::from_u64(0x123456));
+}
+
+#[test]
+fn test_mul_small() {
+ assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35));
+ assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01));
+ assert_eq!(*Big::from_u64(0xffffff/13).mul_small(13), Big::from_u64(0xffffff));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_small_overflow() {
+ Big::from_u64(0x800000).mul_small(2);
+}
+
+#[test]
+fn test_mul_pow2() {
+ assert_eq!(*Big::from_small(0x7).mul_pow2(4), Big::from_small(0x70));
+ assert_eq!(*Big::from_small(0xff).mul_pow2(1), Big::from_u64(0x1fe));
+ assert_eq!(*Big::from_small(0xff).mul_pow2(12), Big::from_u64(0xff000));
+ assert_eq!(*Big::from_small(0x1).mul_pow2(23), Big::from_u64(0x800000));
+ assert_eq!(*Big::from_u64(0x123).mul_pow2(0), Big::from_u64(0x123));
+ assert_eq!(*Big::from_u64(0x123).mul_pow2(7), Big::from_u64(0x9180));
+ assert_eq!(*Big::from_u64(0x123).mul_pow2(15), Big::from_u64(0x918000));
+ assert_eq!(*Big::from_small(0).mul_pow2(23), Big::from_small(0));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow2_overflow_1() {
+ Big::from_u64(0x1).mul_pow2(24);
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow2_overflow_2() {
+ Big::from_u64(0x123).mul_pow2(16);
+}
+
+#[test]
+fn test_mul_pow5() {
+ assert_eq!(*Big::from_small(42).mul_pow5(0), Big::from_small(42));
+ assert_eq!(*Big::from_small(1).mul_pow5(2), Big::from_small(25));
+ assert_eq!(*Big::from_small(1).mul_pow5(4), Big::from_u64(25 * 25));
+ assert_eq!(*Big::from_small(4).mul_pow5(3), Big::from_u64(500));
+ assert_eq!(*Big::from_small(140).mul_pow5(2), Big::from_u64(25 * 140));
+ assert_eq!(*Big::from_small(25).mul_pow5(1), Big::from_small(125));
+ assert_eq!(*Big::from_small(125).mul_pow5(7), Big::from_u64(9765625));
+ assert_eq!(*Big::from_small(0).mul_pow5(127), Big::from_small(0));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow5_overflow_1() {
+ Big::from_small(1).mul_pow5(12);
+}
+
+#[test]
+#[should_panic]
+fn test_mul_pow5_overflow_2() {
+ Big::from_small(230).mul_pow5(8);
+}
+
+#[test]
+fn test_mul_digits() {
+ assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15));
+ assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01));
+ assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2));
+ assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3));
+ assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e));
+ assert_eq!(*Big::from_u64(0xffffff/13).mul_digits(&[13]), Big::from_u64(0xffffff));
+ assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff));
+}
+
+#[test]
+#[should_panic]
+fn test_mul_digits_overflow_1() {
+ Big::from_u64(0x800000).mul_digits(&[2]);
+}
+
+#[test]
+#[should_panic]
+fn test_mul_digits_overflow_2() {
+ Big::from_u64(0x1000).mul_digits(&[0, 0x10]);
+}
+
+#[test]
+fn test_div_rem_small() {
+ let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r);
+ assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0));
+ assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15));
+ assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3));
+ assert_eq!(as_val(Big::from_u64(0xffffff).div_rem_small(123)),
+ (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8));
+ assert_eq!(as_val(Big::from_u64(0x10000).div_rem_small(123)),
+ (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8));
+}
+
+#[test]
+fn test_div_rem() {
+ fn div_rem(n: u64, d: u64) -> (Big, Big) {
+ let mut q = Big::from_small(42);
+ let mut r = Big::from_small(42);
+ Big::from_u64(n).div_rem(&Big::from_u64(d), &mut q, &mut r);
+ (q, r)
+ }
+ assert_eq!(div_rem(1, 1), (Big::from_small(1), Big::from_small(0)));
+ assert_eq!(div_rem(4, 3), (Big::from_small(1), Big::from_small(1)));
+ assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1)));
+ assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0)));
+ assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4)));
+ assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25)));
+ assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0)));
+ assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee)));
+ assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0)));
+}
+
+#[test]
+fn test_is_zero() {
+ assert!(Big::from_small(0).is_zero());
+ assert!(!Big::from_small(3).is_zero());
+ assert!(!Big::from_u64(0x123).is_zero());
+ assert!(!Big::from_u64(0xffffff).sub(&Big::from_u64(0xfffffe)).is_zero());
+ assert!(Big::from_u64(0xffffff).sub(&Big::from_u64(0xffffff)).is_zero());
+}
+
+#[test]
+fn test_get_bit() {
+ let x = Big::from_small(0b1101);
+ assert_eq!(x.get_bit(0), 1);
+ assert_eq!(x.get_bit(1), 0);
+ assert_eq!(x.get_bit(2), 1);
+ assert_eq!(x.get_bit(3), 1);
+ let y = Big::from_u64(1 << 15);
+ assert_eq!(y.get_bit(14), 0);
+ assert_eq!(y.get_bit(15), 1);
+ assert_eq!(y.get_bit(16), 0);
+}
+
+#[test]
+#[should_panic]
+fn test_get_bit_out_of_range() {
+ Big::from_small(42).get_bit(24);
+}
+
+#[test]
+fn test_bit_length() {
+ assert_eq!(Big::from_small(0).bit_length(), 0);
+ assert_eq!(Big::from_small(1).bit_length(), 1);
+ assert_eq!(Big::from_small(5).bit_length(), 3);
+ assert_eq!(Big::from_small(0x18).bit_length(), 5);
+ assert_eq!(Big::from_u64(0x4073).bit_length(), 15);
+ assert_eq!(Big::from_u64(0xffffff).bit_length(), 24);
+}
+
+#[test]
+fn test_ord() {
+ assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
+ assert!(Big::from_u64(0x102) < Big::from_u64(0x201));
+}
+
+#[test]
+fn test_fmt() {
+ assert_eq!(format!("{:?}", Big::from_u64(0)), "0x0");
+ assert_eq!(format!("{:?}", Big::from_u64(0x1)), "0x1");
+ assert_eq!(format!("{:?}", Big::from_u64(0x12)), "0x12");
+ assert_eq!(format!("{:?}", Big::from_u64(0x123)), "0x1_23");
+ assert_eq!(format!("{:?}", Big::from_u64(0x1234)), "0x12_34");
+ assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45");
+ assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56");
+}
+
mod parse;
mod rawfp;
-// Take an float literal, turn it into a string in various ways (that are all trusted
+// Take a float literal, turn it into a string in various ways (that are all trusted
// to be correct) and see if those strings are parsed back to the value of the literal.
// Requires a *polymorphic literal*, i.e. one that can serve as f64 as well as f32.
macro_rules! test_literal {
// except according to those terms.
use std::f64;
-use core::num::flt2dec::strategy::grisu::Fp;
+use core::num::diy_float::Fp;
use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal};
#[test]
fn fp_to_float_half_to_even() {
fn is_normalized(sig: u64) -> bool {
- // intentionally written without {min,max}_sig() as a sanity check
- sig >> 52 == 1 && sig >> 53 == 0
+ // intentionally written without {min,max}_sig() as a sanity check
+ sig >> 52 == 1 && sig >> 53 == 0
}
fn conv(sig: u64) -> u64 {
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::prelude::v1::*;
-use core::num::flt2dec::bignum::tests::Big8x3 as Big;
-
-#[test]
-#[should_panic]
-fn test_from_u64_overflow() {
- Big::from_u64(0x1000000);
-}
-
-#[test]
-fn test_add() {
- assert_eq!(*Big::from_small(3).add(&Big::from_small(4)), Big::from_small(7));
- assert_eq!(*Big::from_small(3).add(&Big::from_small(0)), Big::from_small(3));
- assert_eq!(*Big::from_small(0).add(&Big::from_small(3)), Big::from_small(3));
- assert_eq!(*Big::from_small(3).add(&Big::from_u64(0xfffe)), Big::from_u64(0x10001));
- assert_eq!(*Big::from_u64(0xfedc).add(&Big::from_u64(0x789)), Big::from_u64(0x10665));
- assert_eq!(*Big::from_u64(0x789).add(&Big::from_u64(0xfedc)), Big::from_u64(0x10665));
-}
-
-#[test]
-#[should_panic]
-fn test_add_overflow_1() {
- Big::from_small(1).add(&Big::from_u64(0xffffff));
-}
-
-#[test]
-#[should_panic]
-fn test_add_overflow_2() {
- Big::from_u64(0xffffff).add(&Big::from_small(1));
-}
-
-#[test]
-fn test_add_small() {
- assert_eq!(*Big::from_small(3).add_small(4), Big::from_small(7));
- assert_eq!(*Big::from_small(3).add_small(0), Big::from_small(3));
- assert_eq!(*Big::from_small(0).add_small(3), Big::from_small(3));
- assert_eq!(*Big::from_small(7).add_small(250), Big::from_u64(257));
- assert_eq!(*Big::from_u64(0x7fff).add_small(1), Big::from_u64(0x8000));
- assert_eq!(*Big::from_u64(0x2ffe).add_small(0x35), Big::from_u64(0x3033));
- assert_eq!(*Big::from_small(0xdc).add_small(0x89), Big::from_u64(0x165));
-}
-
-#[test]
-#[should_panic]
-fn test_add_small_overflow() {
- Big::from_u64(0xffffff).add_small(1);
-}
-
-#[test]
-fn test_sub() {
- assert_eq!(*Big::from_small(7).sub(&Big::from_small(4)), Big::from_small(3));
- assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x789)), Big::from_u64(0xfedc));
- assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0xfedc)), Big::from_u64(0x789));
- assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10664)), Big::from_small(1));
- assert_eq!(*Big::from_u64(0x10665).sub(&Big::from_u64(0x10665)), Big::from_small(0));
-}
-
-#[test]
-#[should_panic]
-fn test_sub_underflow_1() {
- Big::from_u64(0x10665).sub(&Big::from_u64(0x10666));
-}
-
-#[test]
-#[should_panic]
-fn test_sub_underflow_2() {
- Big::from_small(0).sub(&Big::from_u64(0x123456));
-}
-
-#[test]
-fn test_mul_small() {
- assert_eq!(*Big::from_small(7).mul_small(5), Big::from_small(35));
- assert_eq!(*Big::from_small(0xff).mul_small(0xff), Big::from_u64(0xfe01));
- assert_eq!(*Big::from_u64(0xffffff/13).mul_small(13), Big::from_u64(0xffffff));
-}
-
-#[test]
-#[should_panic]
-fn test_mul_small_overflow() {
- Big::from_u64(0x800000).mul_small(2);
-}
-
-#[test]
-fn test_mul_pow2() {
- assert_eq!(*Big::from_small(0x7).mul_pow2(4), Big::from_small(0x70));
- assert_eq!(*Big::from_small(0xff).mul_pow2(1), Big::from_u64(0x1fe));
- assert_eq!(*Big::from_small(0xff).mul_pow2(12), Big::from_u64(0xff000));
- assert_eq!(*Big::from_small(0x1).mul_pow2(23), Big::from_u64(0x800000));
- assert_eq!(*Big::from_u64(0x123).mul_pow2(0), Big::from_u64(0x123));
- assert_eq!(*Big::from_u64(0x123).mul_pow2(7), Big::from_u64(0x9180));
- assert_eq!(*Big::from_u64(0x123).mul_pow2(15), Big::from_u64(0x918000));
- assert_eq!(*Big::from_small(0).mul_pow2(23), Big::from_small(0));
-}
-
-#[test]
-#[should_panic]
-fn test_mul_pow2_overflow_1() {
- Big::from_u64(0x1).mul_pow2(24);
-}
-
-#[test]
-#[should_panic]
-fn test_mul_pow2_overflow_2() {
- Big::from_u64(0x123).mul_pow2(16);
-}
-
-#[test]
-fn test_mul_pow5() {
- assert_eq!(*Big::from_small(42).mul_pow5(0), Big::from_small(42));
- assert_eq!(*Big::from_small(1).mul_pow5(2), Big::from_small(25));
- assert_eq!(*Big::from_small(1).mul_pow5(4), Big::from_u64(25 * 25));
- assert_eq!(*Big::from_small(4).mul_pow5(3), Big::from_u64(500));
- assert_eq!(*Big::from_small(140).mul_pow5(2), Big::from_u64(25 * 140));
- assert_eq!(*Big::from_small(25).mul_pow5(1), Big::from_small(125));
- assert_eq!(*Big::from_small(125).mul_pow5(7), Big::from_u64(9765625));
- assert_eq!(*Big::from_small(0).mul_pow5(127), Big::from_small(0));
-}
-
-#[test]
-#[should_panic]
-fn test_mul_pow5_overflow_1() {
- Big::from_small(1).mul_pow5(12);
-}
-
-#[test]
-#[should_panic]
-fn test_mul_pow5_overflow_2() {
- Big::from_small(230).mul_pow5(8);
-}
-
-#[test]
-fn test_mul_digits() {
- assert_eq!(*Big::from_small(3).mul_digits(&[5]), Big::from_small(15));
- assert_eq!(*Big::from_small(0xff).mul_digits(&[0xff]), Big::from_u64(0xfe01));
- assert_eq!(*Big::from_u64(0x123).mul_digits(&[0x56, 0x4]), Big::from_u64(0x4edc2));
- assert_eq!(*Big::from_u64(0x12345).mul_digits(&[0x67]), Big::from_u64(0x7530c3));
- assert_eq!(*Big::from_small(0x12).mul_digits(&[0x67, 0x45, 0x3]), Big::from_u64(0x3ae13e));
- assert_eq!(*Big::from_u64(0xffffff/13).mul_digits(&[13]), Big::from_u64(0xffffff));
- assert_eq!(*Big::from_small(13).mul_digits(&[0x3b, 0xb1, 0x13]), Big::from_u64(0xffffff));
-}
-
-#[test]
-#[should_panic]
-fn test_mul_digits_overflow_1() {
- Big::from_u64(0x800000).mul_digits(&[2]);
-}
-
-#[test]
-#[should_panic]
-fn test_mul_digits_overflow_2() {
- Big::from_u64(0x1000).mul_digits(&[0, 0x10]);
-}
-
-#[test]
-fn test_div_rem_small() {
- let as_val = |(q, r): (&mut Big, u8)| (q.clone(), r);
- assert_eq!(as_val(Big::from_small(0xff).div_rem_small(15)), (Big::from_small(17), 0));
- assert_eq!(as_val(Big::from_small(0xff).div_rem_small(16)), (Big::from_small(15), 15));
- assert_eq!(as_val(Big::from_small(3).div_rem_small(40)), (Big::from_small(0), 3));
- assert_eq!(as_val(Big::from_u64(0xffffff).div_rem_small(123)),
- (Big::from_u64(0xffffff / 123), (0xffffffu64 % 123) as u8));
- assert_eq!(as_val(Big::from_u64(0x10000).div_rem_small(123)),
- (Big::from_u64(0x10000 / 123), (0x10000u64 % 123) as u8));
-}
-
-#[test]
-fn test_div_rem() {
- fn div_rem(n: u64, d: u64) -> (Big, Big) {
- let mut q = Big::from_small(42);
- let mut r = Big::from_small(42);
- Big::from_u64(n).div_rem(&Big::from_u64(d), &mut q, &mut r);
- (q, r)
- }
- assert_eq!(div_rem(1, 1), (Big::from_small(1), Big::from_small(0)));
- assert_eq!(div_rem(4, 3), (Big::from_small(1), Big::from_small(1)));
- assert_eq!(div_rem(1, 7), (Big::from_small(0), Big::from_small(1)));
- assert_eq!(div_rem(45, 9), (Big::from_small(5), Big::from_small(0)));
- assert_eq!(div_rem(103, 9), (Big::from_small(11), Big::from_small(4)));
- assert_eq!(div_rem(123456, 77), (Big::from_u64(1603), Big::from_small(25)));
- assert_eq!(div_rem(0xffff, 1), (Big::from_u64(0xffff), Big::from_small(0)));
- assert_eq!(div_rem(0xeeee, 0xffff), (Big::from_small(0), Big::from_u64(0xeeee)));
- assert_eq!(div_rem(2_000_000, 2), (Big::from_u64(1_000_000), Big::from_u64(0)));
-}
-
-#[test]
-fn test_is_zero() {
- assert!(Big::from_small(0).is_zero());
- assert!(!Big::from_small(3).is_zero());
- assert!(!Big::from_u64(0x123).is_zero());
- assert!(!Big::from_u64(0xffffff).sub(&Big::from_u64(0xfffffe)).is_zero());
- assert!(Big::from_u64(0xffffff).sub(&Big::from_u64(0xffffff)).is_zero());
-}
-
-#[test]
-fn test_get_bit() {
- let x = Big::from_small(0b1101);
- assert_eq!(x.get_bit(0), 1);
- assert_eq!(x.get_bit(1), 0);
- assert_eq!(x.get_bit(2), 1);
- assert_eq!(x.get_bit(3), 1);
- let y = Big::from_u64(1 << 15);
- assert_eq!(y.get_bit(14), 0);
- assert_eq!(y.get_bit(15), 1);
- assert_eq!(y.get_bit(16), 0);
-}
-
-#[test]
-#[should_panic]
-fn test_get_bit_out_of_range() {
- Big::from_small(42).get_bit(24);
-}
-
-#[test]
-fn test_bit_length() {
- assert_eq!(Big::from_small(0).bit_length(), 0);
- assert_eq!(Big::from_small(1).bit_length(), 1);
- assert_eq!(Big::from_small(5).bit_length(), 3);
- assert_eq!(Big::from_small(0x18).bit_length(), 5);
- assert_eq!(Big::from_u64(0x4073).bit_length(), 15);
- assert_eq!(Big::from_u64(0xffffff).bit_length(), 24);
-}
-
-#[test]
-fn test_ord() {
- assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
- assert!(Big::from_u64(0x102) < Big::from_u64(0x201));
-}
-
-#[test]
-fn test_fmt() {
- assert_eq!(format!("{:?}", Big::from_u64(0)), "0x0");
- assert_eq!(format!("{:?}", Big::from_u64(0x1)), "0x1");
- assert_eq!(format!("{:?}", Big::from_u64(0x12)), "0x12");
- assert_eq!(format!("{:?}", Big::from_u64(0x123)), "0x1_23");
- assert_eq!(format!("{:?}", Big::from_u64(0x1234)), "0x12_34");
- assert_eq!(format!("{:?}", Big::from_u64(0x12345)), "0x1_23_45");
- assert_eq!(format!("{:?}", Big::from_u64(0x123456)), "0x12_34_56");
-}
-
pub use test::Bencher;
mod estimator;
-mod bignum;
mod strategy {
mod dragon;
mod grisu;
use std::{i16, f64};
use super::super::*;
use core::num::flt2dec::*;
-use core::num::flt2dec::bignum::Big32x40 as Big;
+use core::num::bignum::Big32x40 as Big;
use core::num::flt2dec::strategy::dragon::*;
#[test]
mod flt2dec;
mod dec2flt;
+mod bignum;
/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T) where
assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
}
+ #[test]
+ fn test_leading_plus() {
+ assert_eq!("+127".parse::<u8>().ok(), Some(127u8));
+ assert_eq!("+9223372036854775807".parse::<i64>().ok(), Some(9223372036854775807i64));
+ }
+
#[test]
fn test_invalid() {
assert_eq!("--129".parse::<i8>().ok(), None);
+ assert_eq!("++129".parse::<i8>().ok(), None);
assert_eq!("Съешь".parse::<u8>().ok(), None);
}
#[test]
fn test_empty() {
assert_eq!("-".parse::<i8>().ok(), None);
+ assert_eq!("+".parse::<i8>().ok(), None);
assert_eq!("".parse::<u8>().ok(), None);
}
+
+ macro_rules! test_impl_from {
+ ($fn_name: ident, $Small: ty, $Large: ty) => {
+ #[test]
+ fn $fn_name() {
+ let small_max = <$Small>::max_value();
+ let small_min = <$Small>::min_value();
+ let large_max: $Large = small_max.into();
+ let large_min: $Large = small_min.into();
+ assert_eq!(large_max as $Small, small_max);
+ assert_eq!(large_min as $Small, small_min);
+ }
+ }
+ }
+
+ // Unsigned -> Unsigned
+ test_impl_from! { test_u8u16, u8, u16 }
+ test_impl_from! { test_u8u32, u8, u32 }
+ test_impl_from! { test_u8u64, u8, u64 }
+ test_impl_from! { test_u8usize, u8, usize }
+ test_impl_from! { test_u16u32, u16, u32 }
+ test_impl_from! { test_u16u64, u16, u64 }
+ test_impl_from! { test_u32u64, u32, u64 }
+
+ // Signed -> Signed
+ test_impl_from! { test_i8i16, i8, i16 }
+ test_impl_from! { test_i8i32, i8, i32 }
+ test_impl_from! { test_i8i64, i8, i64 }
+ test_impl_from! { test_i8isize, i8, isize }
+ test_impl_from! { test_i16i32, i16, i32 }
+ test_impl_from! { test_i16i64, i16, i64 }
+ test_impl_from! { test_i32i64, i32, i64 }
+
+ // Unsigned -> Signed
+ test_impl_from! { test_u8i16, u8, i16 }
+ test_impl_from! { test_u8i32, u8, i32 }
+ test_impl_from! { test_u8i64, u8, i64 }
+ test_impl_from! { test_u16i32, u16, i32 }
+ test_impl_from! { test_u16i64, u16, i64 }
+ test_impl_from! { test_u32i64, u32, i64 }
}
#![feature(unique)]
#![cfg_attr(test, feature(rustc_private, rand, vec_push_all))]
-#[cfg(test)] #[macro_use] extern crate log;
+#[cfg(test)]
+#[macro_use]
+extern crate log;
extern crate libc;
impl Error {
fn new() -> Error {
- Error {
- _unused: (),
- }
+ Error { _unused: () }
}
}
impl Drop for Bytes {
fn drop(&mut self) {
- unsafe { libc::free(*self.ptr as *mut _); }
+ unsafe {
+ libc::free(*self.ptr as *mut _);
+ }
}
}
deflate_bytes_internal(bytes, LZ_NORM | TDEFL_WRITE_ZLIB_HEADER)
}
-fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result<Bytes,Error> {
+fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> Result<Bytes, Error> {
unsafe {
let mut outsz: size_t = 0;
let res = tinfl_decompress_mem_to_heap(bytes.as_ptr() as *const _,
}
/// Decompress a buffer, without parsing any sort of header on the input.
-pub fn inflate_bytes(bytes: &[u8]) -> Result<Bytes,Error> {
+pub fn inflate_bytes(bytes: &[u8]) -> Result<Bytes, Error> {
inflate_bytes_internal(bytes, 0)
}
/// Decompress a buffer that starts with a zlib header.
-pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result<Bytes,Error> {
+pub fn inflate_bytes_zlib(bytes: &[u8]) -> Result<Bytes, Error> {
inflate_bytes_internal(bytes, TINFL_FLAG_PARSE_ZLIB_HEADER)
}
let cmp = deflate_bytes(&input);
let out = inflate_bytes(&cmp).unwrap();
debug!("{} bytes deflated to {} ({:.1}% size)",
- input.len(), cmp.len(),
+ input.len(),
+ cmp.len(),
100.0 * ((cmp.len() as f64) / (input.len() as f64)));
assert_eq!(&*input, &*out);
}
/// The descriptor string representing the name of the format desired for
/// this argument, this can be empty or any number of characters, although
/// it is required to be one word.
- pub ty: &'a str
+ pub ty: &'a str,
}
/// Enum describing where an argument for a format can be located.
}
/// The parser structure for interpreting the input format string. This is
-/// modelled as an iterator over `Piece` structures to form a stream of tokens
+/// modeled as an iterator over `Piece` structures to form a stream of tokens
/// being output.
///
/// This is a recursive-descent parser for the sake of simplicity, and if
/// returned, otherwise the character is consumed and true is returned.
fn consume(&mut self, c: char) -> bool {
if let Some(&(_, maybe)) = self.cur.peek() {
- if c == maybe { self.cur.next(); true } else { false }
+ if c == maybe {
+ self.cur.next();
+ true
+ } else {
+ false
+ }
} else {
false
}
/// character
fn ws(&mut self) {
while let Some(&(_, c)) = self.cur.peek() {
- if c.is_whitespace() { self.cur.next(); } else { break }
+ if c.is_whitespace() {
+ self.cur.next();
+ } else {
+ break
+ }
}
}
// we may not consume the character, peek the iterator
while let Some(&(pos, c)) = self.cur.peek() {
match c {
- '{' | '}' => { return &self.input[start..pos]; }
- _ => { self.cur.next(); }
+ '{' | '}' => {
+ return &self.input[start..pos];
+ }
+ _ => {
+ self.cur.next();
+ }
}
}
&self.input[start..self.input.len()]
Some(&(_, c)) if c.is_alphabetic() => {
ArgumentNamed(self.word())
}
- _ => ArgumentNext
+ _ => ArgumentNext,
}
}
}
width: CountImplied,
ty: &self.input[..0],
};
- if !self.consume(':') { return spec }
+ if !self.consume(':') {
+ return spec
+ }
// fill character
if let Some(&(_, c)) = self.cur.peek() {
/// width.
fn count(&mut self) -> Count<'a> {
if let Some(i) = self.integer() {
- if self.consume('$') { CountIsParam(i) } else { CountIs(i) }
+ if self.consume('$') {
+ CountIsParam(i)
+ } else {
+ CountIs(i)
+ }
} else {
let tmp = self.cur.clone();
let word = self.word();
/// characters.
fn word(&mut self) -> &'a str {
let start = match self.cur.peek() {
- Some(&(pos, c)) if c.is_xid_start() => { self.cur.next(); pos }
- _ => { return &self.input[..0]; }
+ Some(&(pos, c)) if c.is_xid_start() => {
+ self.cur.next();
+ pos
+ }
+ _ => {
+ return &self.input[..0];
+ }
};
while let Some(&(pos, c)) = self.cur.peek() {
if c.is_xid_continue() {
break
}
}
- if found { Some(cur) } else { None }
+ if found {
+ Some(cur)
+ } else {
+ None
+ }
}
}
same("\\}}", &[String("\\"), String("}")]);
}
- #[test] fn invalid01() { musterr("{") }
- #[test] fn invalid02() { musterr("}") }
- #[test] fn invalid04() { musterr("{3a}") }
- #[test] fn invalid05() { musterr("{:|}") }
- #[test] fn invalid06() { musterr("{:>>>}") }
+ #[test]
+ fn invalid01() {
+ musterr("{")
+ }
+ #[test]
+ fn invalid02() {
+ musterr("}")
+ }
+ #[test]
+ fn invalid04() {
+ musterr("{3a}")
+ }
+ #[test]
+ fn invalid05() {
+ musterr("{:|}")
+ }
+ #[test]
+ fn invalid06() {
+ musterr("{:>>>}")
+ }
#[test]
fn format_nothing() {
- same("{}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: fmtdflt(),
- })]);
+ same("{}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: fmtdflt(),
+ })]);
}
#[test]
fn format_position() {
- same("{3}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: fmtdflt(),
- })]);
+ same("{3}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: fmtdflt(),
+ })]);
}
#[test]
fn format_position_nothing_else() {
- same("{3:}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: fmtdflt(),
- })]);
+ same("{3:}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: fmtdflt(),
+ })]);
}
#[test]
fn format_type() {
- same("{3:a}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "a",
- },
- })]);
+ same("{3:a}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "a",
+ },
+ })]);
}
#[test]
fn format_align_fill() {
- same("{3:>}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: None,
- align: AlignRight,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
- same("{3:0<}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: Some('0'),
- align: AlignLeft,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
- same("{3:*<abcd}", &[NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: Some('*'),
- align: AlignLeft,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "abcd",
- },
- })]);
+ same("{3:>}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: AlignRight,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
+ same("{3:0<}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: Some('0'),
+ align: AlignLeft,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
+ same("{3:*<abcd}",
+ &[NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: Some('*'),
+ align: AlignLeft,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "abcd",
+ },
+ })]);
}
#[test]
fn format_counts() {
- same("{:10s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountImplied,
- width: CountIs(10),
- ty: "s",
- },
- })]);
- same("{:10$.10s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIs(10),
- width: CountIsParam(10),
- ty: "s",
- },
- })]);
- same("{:.*s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIsNextParam,
- width: CountImplied,
- ty: "s",
- },
- })]);
- same("{:.10$s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIsParam(10),
- width: CountImplied,
- ty: "s",
- },
- })]);
- same("{:a$.b$s}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountIsName("b"),
- width: CountIsName("a"),
- ty: "s",
- },
- })]);
+ same("{:10s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountImplied,
+ width: CountIs(10),
+ ty: "s",
+ },
+ })]);
+ same("{:10$.10s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIs(10),
+ width: CountIsParam(10),
+ ty: "s",
+ },
+ })]);
+ same("{:.*s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIsNextParam,
+ width: CountImplied,
+ ty: "s",
+ },
+ })]);
+ same("{:.10$s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIsParam(10),
+ width: CountImplied,
+ ty: "s",
+ },
+ })]);
+ same("{:a$.b$s}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountIsName("b"),
+ width: CountIsName("a"),
+ ty: "s",
+ },
+ })]);
}
#[test]
fn format_flags() {
- same("{:-}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: (1 << FlagSignMinus as u32),
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
- same("{:+#}", &[NextArgument(Argument {
- position: ArgumentNext,
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
- precision: CountImplied,
- width: CountImplied,
- ty: "",
- },
- })]);
+ same("{:-}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: (1 << FlagSignMinus as u32),
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
+ same("{:+#}",
+ &[NextArgument(Argument {
+ position: ArgumentNext,
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: (1 << FlagSignPlus as u32) | (1 << FlagAlternate as u32),
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "",
+ },
+ })]);
}
#[test]
fn format_mixture() {
- same("abcd {3:a} efg", &[String("abcd "), NextArgument(Argument {
- position: ArgumentIs(3),
- format: FormatSpec {
- fill: None,
- align: AlignUnknown,
- flags: 0,
- precision: CountImplied,
- width: CountImplied,
- ty: "a",
- },
- }), String(" efg")]);
+ same("abcd {3:a} efg",
+ &[String("abcd "),
+ NextArgument(Argument {
+ position: ArgumentIs(3),
+ format: FormatSpec {
+ fill: None,
+ align: AlignUnknown,
+ flags: 0,
+ precision: CountImplied,
+ width: CountImplied,
+ ty: "a",
+ },
+ }),
+ String(" efg")]);
}
}
fn graph_id(&'a self) -> Id<'a>;
/// Maps `n` to a unique identifier with respect to `self`. The
- /// implementer is responsible for ensuring that the returned name
+ /// implementor is responsible for ensuring that the returned name
/// is a valid DOT identifier.
fn node_id(&'a self, n: &N) -> Id<'a>;
/// that is bound by the self lifetime `'a`.
///
/// The `nodes` and `edges` method each return instantiations of
-/// `Cow<[T]>` to leave implementers the freedom to create
+/// `Cow<[T]>` to leave implementors the freedom to create
/// entirely new vectors or to pass back slices into internally owned
/// vectors.
pub trait GraphWalk<'a, N: Clone, E: Clone> {
html_playground_url = "https://play.rust-lang.org/",
issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")]
#![cfg_attr(test, feature(test))]
+#![cfg_attr(not(feature = "cargo-build"), feature(cfg_target_vendor))]
//! Bindings for the C standard library and other platform libraries
//!
#![allow(bad_style, raw_pointer_derive)]
#![cfg_attr(target_os = "nacl", allow(unused_imports))]
-#[cfg(feature = "cargo-build")] extern crate std as core;
+#[cfg(feature = "cargo-build")]
+extern crate std as core;
-#[cfg(test)] extern crate std;
-#[cfg(test)] extern crate test;
+#[cfg(test)]
+extern crate std;
+#[cfg(test)]
+extern crate test;
// Explicit export lists for the intersection (provided here) mean that
// you can write more-platform-agnostic code if you stick to just these
//
// So the following exports don't follow any particular plan.
-#[cfg(unix)] pub use consts::os::sysconf::*;
-
-#[cfg(unix)] pub use funcs::posix88::mman::*;
-#[cfg(unix)] pub use funcs::posix88::dirent::*;
-#[cfg(unix)] pub use funcs::posix88::net::*;
-#[cfg(unix)] pub use funcs::posix01::stat_::*;
-#[cfg(unix)] pub use funcs::posix01::unistd::*;
-#[cfg(unix)] pub use funcs::posix01::resource::*;
-
-
-#[cfg(windows)] pub use funcs::extra::kernel32::*;
-#[cfg(windows)] pub use funcs::extra::winsock::*;
-#[cfg(windows)] pub use funcs::extra::msvcrt::*;
+#[cfg(unix)]
+pub use consts::os::sysconf::*;
+
+#[cfg(unix)]
+pub use funcs::posix88::mman::*;
+#[cfg(unix)]
+pub use funcs::posix88::dirent::*;
+#[cfg(unix)]
+pub use funcs::posix88::net::*;
+#[cfg(unix)]
+pub use funcs::posix01::stat_::*;
+#[cfg(unix)]
+pub use funcs::posix01::unistd::*;
+#[cfg(unix)]
+pub use funcs::posix01::resource::*;
+
+
+#[cfg(windows)]
+pub use funcs::extra::kernel32::*;
+#[cfg(windows)]
+pub use funcs::extra::winsock::*;
+#[cfg(windows)]
+pub use funcs::extra::msvcrt::*;
// On NaCl, these libraries are static. Thus it would be a Bad Idea to link them
// in when creating a test crate.
-#[cfg(not(any(windows, target_env = "musl", all(target_os = "nacl", test))))]
+#[cfg(not(any(windows,
+ target_env = "musl",
+ all(target_os = "nacl", test),
+ all(target_os = "netbsd", target_vendor = "rumprun"))))]
#[link(name = "c")]
#[link(name = "m")]
-extern {}
+extern {
+}
// When compiling rust with musl, statically include libc.a in liblibc.rlib.
// A cargo build of the libc crate will therefore automatically pick up the
// libc.a symbols because liblibc is transitively linked to by the stdlib.
#[cfg(all(target_env = "musl", not(feature = "cargo-build"), not(test)))]
#[link(name = "c", kind = "static")]
-extern {}
+extern {
+}
#[cfg(all(windows, target_env = "msvc"))]
#[link(name = "kernel32")]
#[link(name = "shell32")]
#[link(name = "msvcrt")]
-extern {}
+extern {
+}
// libnacl provides functions that require a trip through the IRT to work.
// ie: _exit, mmap, nanosleep, etc. Anything that would otherwise require a trip
// to the kernel.
#[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))]
#[link(name = "nacl", kind = "static")]
-extern {}
+extern {
+}
// pnaclmm provides a number of functions that the toolchain's Clang emits calls
// to when codegening atomic ops. All the functions within wrap various atomic
// optimizations on the whole pnaclmm foreach binary built).
#[cfg(all(target_os = "nacl", not(feature = "cargo-build"), not(test)))]
#[link(name = "pnaclmm", kind = "static")]
-extern {}
+extern {
+}
pub mod types {
pub enum DIR {}
pub enum dirent_t {}
}
- pub mod posix01 {}
- pub mod posix08 {}
- pub mod bsd44 {}
+ pub mod posix01 {
+ }
+ pub mod posix08 {
+ }
+ pub mod bsd44 {
+ }
}
// Standard types that are scalar but vary by OS and arch.
pub mod os {
pub mod common {
pub mod posix01 {
- use types::common::c95::{c_void};
- use types::os::arch::c95::{c_char, c_ulong, size_t,
- time_t, suseconds_t, c_long};
+ use types::common::c95::c_void;
+ use types::os::arch::c95::{c_char, c_ulong, size_t, time_t, suseconds_t, c_long};
#[cfg(not(target_os = "nacl"))]
pub type pthread_t = c_ulong;
pub type rlim_t = u64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct glob_t {
+ #[derive(Copy, Clone)]
+ pub struct glob_t {
pub gl_pathc: size_t,
pub gl_pathv: *mut *mut c_char,
- pub gl_offs: size_t,
+ pub gl_offs: size_t,
pub __unused1: *mut c_void,
pub __unused2: *mut c_void,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timeval {
+ #[derive(Copy, Clone)]
+ pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timespec {
+ #[derive(Copy, Clone)]
+ pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub ru_msgrcv: c_long,
pub ru_nsignals: c_long,
pub ru_nvcsw: c_long,
- pub ru_nivcsw: c_long
+ pub ru_nivcsw: c_long,
}
}
pub mod bsd44 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = u32;
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_storage {
+ #[derive(Copy)]
+ pub struct sockaddr_storage {
pub ss_family: sa_family_t,
pub __ss_align: isize,
#[cfg(target_pointer_width = "32")]
pub __ss_pad2: [u8; 128 - 2 * 8],
}
impl ::core::clone::Clone for sockaddr_storage {
- fn clone(&self) -> sockaddr_storage { *self }
+ fn clone(&self) -> sockaddr_storage {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_addr: in_addr,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in_addr {
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in6_addr {
- pub s6_addr: [u16; 8]
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u16; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct addrinfo {
+ #[derive(Copy, Clone)]
+ pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub ai_next: *mut addrinfo,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_un {
+ #[derive(Copy)]
+ pub struct sockaddr_un {
pub sun_family: sa_family_t,
- pub sun_path: [c_char; 108]
+ pub sun_path: [c_char; 108],
}
impl ::core::clone::Clone for sockaddr_un {
- fn clone(&self) -> sockaddr_un { *self }
+ fn clone(&self) -> sockaddr_un {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ifaddrs {
+ #[derive(Copy, Clone)]
+ pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub ifa_addr: *mut sockaddr,
pub ifa_netmask: *mut sockaddr,
pub ifa_ifu: *mut sockaddr, // FIXME This should be a union
- pub ifa_data: *mut c_void
+ pub ifa_data: *mut c_void,
}
}
use types::os::arch::c95::{c_short, c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t, ino_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
pub type nlink_t = u32;
pub type blksize_t = i32;
pub type blkcnt_t = i32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub __pad1: c_short,
pub st_ino: ino_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct pthread_attr_t {
- pub __size: [u32; 9]
+ #[derive(Copy, Clone)]
+ pub struct pthread_attr_t {
+ pub __size: [u32; 9],
}
}
pub type blkcnt_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: c_ulonglong,
pub __pad0: [c_uchar; 4],
pub __st_ino: c_long,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct pthread_attr_t {
- pub __size: [u32; 9]
+ #[derive(Copy, Clone)]
+ pub struct pthread_attr_t {
+ pub __size: [u32; 9],
}
}
use types::os::arch::c95::{c_long, c_ulong, time_t};
use types::os::arch::posix88::{gid_t, ino_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
pub type nlink_t = u32;
pub type blksize_t = i32;
pub type blkcnt_t = i32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: c_ulong,
pub st_pad1: [c_long; 3],
pub st_ino: ino_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct pthread_attr_t {
- pub __size: [u32; 9]
+ #[derive(Copy, Clone)]
+ pub struct pthread_attr_t {
+ pub __size: [u32; 9],
}
}
- pub mod posix08 {}
- pub mod bsd44 {}
+ pub mod posix08 {
+ }
+ pub mod bsd44 {
+ }
pub mod extra {
use types::os::arch::c95::{c_ushort, c_int, c_uchar};
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_ll {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_ll {
pub sll_family: c_ushort,
pub sll_protocol: c_ushort,
pub sll_ifindex: c_int,
pub sll_hatype: c_ushort,
pub sll_pkttype: c_uchar,
pub sll_halen: c_uchar,
- pub sll_addr: [c_uchar; 8]
+ pub sll_addr: [c_uchar; 8],
}
}
use types::os::arch::c95::{c_int, c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t, ino_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
pub type nlink_t = u64;
pub type blksize_t = i64;
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_nlink: nlink_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct pthread_attr_t {
- pub __size: [u64; 7]
+ #[derive(Copy, Clone)]
+ pub struct pthread_attr_t {
+ pub __size: [u64; 7],
}
}
#[cfg(target_arch = "aarch64")]
use types::os::arch::c95::{c_int, c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t, ino_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
pub type nlink_t = u32;
pub type blksize_t = i32;
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: mode_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct pthread_attr_t {
- pub __size: [u64; 8]
+ #[derive(Copy, Clone)]
+ pub struct pthread_attr_t {
+ pub __size: [u64; 8],
}
}
pub mod posix08 {
}
pub mod extra {
use types::os::arch::c95::{c_ushort, c_int, c_uchar};
- #[derive(Copy, Clone)] pub struct sockaddr_ll {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_ll {
pub sll_family: c_ushort,
pub sll_protocol: c_ushort,
pub sll_ifindex: c_int,
pub sll_hatype: c_ushort,
pub sll_pkttype: c_uchar,
pub sll_halen: c_uchar,
- pub sll_addr: [c_uchar; 8]
+ pub sll_addr: [c_uchar; 8],
}
}
pub mod os {
pub mod common {
pub mod posix01 {
- use types::common::c95::{c_void};
- use types::os::arch::c95::{c_char, c_int, size_t,
- time_t, suseconds_t, c_long};
- use types::os::arch::c99::{uintptr_t};
+ use types::common::c95::c_void;
+ use types::os::arch::c95::{c_char, c_int, size_t, time_t, suseconds_t, c_long};
+ use types::os::arch::c99::uintptr_t;
pub type pthread_t = uintptr_t;
pub type rlim_t = i64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct glob_t {
- pub gl_pathc: size_t,
+ #[derive(Copy, Clone)]
+ pub struct glob_t {
+ pub gl_pathc: size_t,
pub __unused1: size_t,
- pub gl_offs: size_t,
+ pub gl_offs: size_t,
pub __unused2: c_int,
- pub gl_pathv: *mut *mut c_char,
+ pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timeval {
+ #[derive(Copy, Clone)]
+ pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timespec {
+ #[derive(Copy, Clone)]
+ pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub ru_msgrcv: c_long,
pub ru_nsignals: c_long,
pub ru_nvcsw: c_long,
- pub ru_nivcsw: c_long
+ pub ru_nivcsw: c_long,
}
}
pub mod bsd44 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = u32;
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_storage {
+ #[derive(Copy)]
+ pub struct sockaddr_storage {
pub ss_len: u8,
pub ss_family: sa_family_t,
pub __ss_pad1: [u8; 6],
pub __ss_pad2: [u8; 112],
}
impl ::core::clone::Clone for sockaddr_storage {
- fn clone(&self) -> sockaddr_storage { *self }
+ fn clone(&self) -> sockaddr_storage {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in_addr {
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in6_addr {
- pub s6_addr: [u16; 8]
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u16; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct addrinfo {
+ #[derive(Copy, Clone)]
+ pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub ai_next: *mut addrinfo,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_un {
+ #[derive(Copy)]
+ pub struct sockaddr_un {
pub sun_len: u8,
pub sun_family: sa_family_t,
- pub sun_path: [c_char; 104]
+ pub sun_path: [c_char; 104],
}
impl ::core::clone::Clone for sockaddr_un {
- fn clone(&self) -> sockaddr_un { *self }
+ fn clone(&self) -> sockaddr_un {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ifaddrs {
+ #[derive(Copy, Clone)]
+ pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub ifa_addr: *mut sockaddr,
pub ifa_netmask: *mut sockaddr,
pub ifa_dstaddr: *mut sockaddr,
- pub ifa_data: *mut c_void
+ pub ifa_data: *mut c_void,
}
pub type ssize_t = i32;
}
pub mod posix01 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::common::c99::{uint32_t, int32_t};
use types::os::arch::c95::{c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t, ino_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
pub type nlink_t = u16;
pub type blksize_t = u32;
pub type blkcnt_t = i64;
pub type fflags_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: mode_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
pub type ssize_t = i64;
}
pub mod posix01 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::common::c99::{uint32_t, int32_t};
use types::os::arch::c95::{c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t, ino_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
pub type nlink_t = u16;
pub type blksize_t = u32;
pub type blkcnt_t = i64;
pub type fflags_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: mode_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
pub mod os {
pub mod common {
pub mod posix01 {
- use types::common::c95::{c_void};
- use types::os::arch::c95::{c_char, c_int, size_t,
- time_t, suseconds_t, c_long};
- use types::os::arch::c99::{uintptr_t};
+ use types::common::c95::c_void;
+ use types::os::arch::c95::{c_char, c_int, size_t, time_t, suseconds_t, c_long};
+ use types::os::arch::c99::uintptr_t;
pub type pthread_t = uintptr_t;
pub type rlim_t = i64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct glob_t {
- pub gl_pathc: size_t,
+ #[derive(Copy, Clone)]
+ pub struct glob_t {
+ pub gl_pathc: size_t,
pub __unused1: size_t,
- pub gl_offs: size_t,
+ pub gl_offs: size_t,
pub __unused2: c_int,
- pub gl_pathv: *mut *mut c_char,
+ pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timeval {
+ #[derive(Copy, Clone)]
+ pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timespec {
+ #[derive(Copy, Clone)]
+ pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub ru_msgrcv: c_long,
pub ru_nsignals: c_long,
pub ru_nvcsw: c_long,
- pub ru_nivcsw: c_long
+ pub ru_nivcsw: c_long,
}
}
pub mod bsd44 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = u32;
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_storage {
+ #[derive(Copy)]
+ pub struct sockaddr_storage {
pub ss_len: u8,
pub ss_family: sa_family_t,
pub __ss_pad1: [u8; 6],
pub __ss_pad2: [u8; 112],
}
impl ::core::clone::Clone for sockaddr_storage {
- fn clone(&self) -> sockaddr_storage { *self }
+ fn clone(&self) -> sockaddr_storage {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in_addr {
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in6_addr {
- pub s6_addr: [u16; 8]
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u16; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct addrinfo {
+ #[derive(Copy, Clone)]
+ pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub ai_next: *mut addrinfo,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_un {
+ #[derive(Copy)]
+ pub struct sockaddr_un {
pub sun_len: u8,
pub sun_family: sa_family_t,
- pub sun_path: [c_char; 104]
+ pub sun_path: [c_char; 104],
}
impl ::core::clone::Clone for sockaddr_un {
- fn clone(&self) -> sockaddr_un { *self }
+ fn clone(&self) -> sockaddr_un {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ifaddrs {
+ #[derive(Copy, Clone)]
+ pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub ifa_addr: *mut sockaddr,
pub ifa_netmask: *mut sockaddr,
pub ifa_dstaddr: *mut sockaddr,
- pub ifa_data: *mut c_void
+ pub ifa_data: *mut c_void,
}
}
pub type ssize_t = i64;
}
pub mod posix01 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::common::c99::{uint16_t, uint32_t, int32_t, uint64_t, int64_t};
use types::os::arch::c95::{c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
pub type nlink_t = u16;
pub type blksize_t = uint32_t;
pub type fflags_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_ino: ino_t,
pub st_nlink: nlink_t,
pub st_dev: dev_t,
pub st_qspare2: int64_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
pub mod os {
pub mod common {
pub mod posix01 {
- use types::common::c95::{c_void};
- use types::os::arch::c95::{c_char, c_int, size_t,
- time_t, suseconds_t, c_long};
- use types::os::arch::c99::{uintptr_t};
+ use types::common::c95::c_void;
+ use types::os::arch::c95::{c_char, c_int, size_t, time_t, suseconds_t, c_long};
+ use types::os::arch::c99::uintptr_t;
pub type pthread_t = uintptr_t;
pub type rlim_t = u64;
#[cfg(target_os = "bitrig")]
#[repr(C)]
- #[derive(Copy, Clone)] pub struct glob_t {
- pub gl_pathc: c_int,
+ #[derive(Copy, Clone)]
+ pub struct glob_t {
+ pub gl_pathc: c_int,
pub gl_matchc: c_int,
- pub gl_offs: c_int,
- pub gl_flags: c_int,
- pub gl_pathv: *mut *mut c_char,
+ pub gl_offs: c_int,
+ pub gl_flags: c_int,
+ pub gl_pathv: *mut *mut c_char,
pub __unused1: *mut c_void,
pub __unused2: *mut c_void,
pub __unused3: *mut c_void,
pub __unused7: *mut c_void,
}
- #[cfg(any(target_os = "netbsd", target_os="openbsd"))]
+ #[cfg(target_os = "netbsd")]
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct glob_t {
+ pub gl_pathc: size_t,
+ pub gl_matchc: size_t,
+ pub gl_offs: size_t,
+ pub gl_flags: c_int,
+ pub gl_pathv: *mut *mut c_char,
+ pub __unused1: *mut c_void,
+ pub __unused2: *mut c_void,
+ pub __unused3: *mut c_void,
+ pub __unused4: *mut c_void,
+ pub __unused5: *mut c_void,
+ pub __unused6: *mut c_void,
+ }
+
+ #[cfg(target_os = "openbsd")]
#[repr(C)]
- #[derive(Copy, Clone)] pub struct glob_t {
- pub gl_pathc: c_int,
+ #[derive(Copy, Clone)]
+ pub struct glob_t {
+ pub gl_pathc: c_int,
pub __unused1: c_int,
- pub gl_offs: c_int,
+ pub gl_offs: c_int,
pub __unused2: c_int,
- pub gl_pathv: *mut *mut c_char,
+ pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timeval {
+ #[derive(Copy, Clone)]
+ pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timespec {
+ #[derive(Copy, Clone)]
+ pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub ru_msgrcv: c_long,
pub ru_nsignals: c_long,
pub ru_nvcsw: c_long,
- pub ru_nivcsw: c_long
+ pub ru_nivcsw: c_long,
}
}
pub mod bsd44 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = u32;
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_storage {
+ #[derive(Copy)]
+ pub struct sockaddr_storage {
pub ss_len: u8,
pub ss_family: sa_family_t,
pub __ss_pad1: [u8; 6],
pub __ss_pad3: [u8; 240],
}
impl ::core::clone::Clone for sockaddr_storage {
- fn clone(&self) -> sockaddr_storage { *self }
+ fn clone(&self) -> sockaddr_storage {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in_addr {
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in6_addr {
- pub s6_addr: [u16; 8]
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u16; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
+ #[cfg(not(target_os = "netbsd"))]
#[repr(C)]
- #[derive(Copy, Clone)] pub struct addrinfo {
+ #[derive(Copy, Clone)]
+ pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub ai_canonname: *mut c_char,
pub ai_next: *mut addrinfo,
}
+ #[cfg(target_os = "netbsd")]
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct addrinfo {
+ pub ai_flags: c_int,
+ pub ai_family: c_int,
+ pub ai_socktype: c_int,
+ pub ai_protocol: c_int,
+ pub ai_addrlen: socklen_t,
+ pub ai_canonname: *mut c_char,
+ pub ai_addr: *mut sockaddr,
+ pub ai_next: *mut addrinfo,
+ }
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_un {
+ #[derive(Copy)]
+ pub struct sockaddr_un {
pub sun_len: u8,
pub sun_family: sa_family_t,
- pub sun_path: [c_char; 104]
+ pub sun_path: [c_char; 104],
}
impl ::core::clone::Clone for sockaddr_un {
- fn clone(&self) -> sockaddr_un { *self }
+ fn clone(&self) -> sockaddr_un {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ifaddrs {
+ #[derive(Copy, Clone)]
+ pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub ifa_addr: *mut sockaddr,
pub ifa_netmask: *mut sockaddr,
pub ifa_dstaddr: *mut sockaddr,
- pub ifa_data: *mut c_void
+ pub ifa_data: *mut c_void,
}
}
}
pub type uintmax_t = u64;
}
pub mod posix88 {
- use types::os::arch::c95::{c_long};
+ use types::os::arch::c95::c_long;
pub type off_t = i64;
pub type dev_t = i32;
pub type pid_t = i32;
pub type ssize_t = c_long;
}
pub mod posix01 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::common::c99::{uint32_t, uint64_t};
use types::os::arch::c95::{c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t};
use types::os::arch::posix88::{mode_t, off_t};
- use types::os::arch::posix88::{uid_t};
+ use types::os::arch::posix88::uid_t;
+ #[cfg(target_os = "netbsd")]
+ use types::os::arch::c95::{c_int, c_uint};
pub type nlink_t = uint32_t;
pub type blksize_t = uint32_t;
pub type blkcnt_t = i64;
pub type fflags_t = u32; // type not declared, but struct stat have u_int32_t
+ #[cfg(not(target_os = "netbsd"))]
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_mode: mode_t,
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_birthtime: time_t,
pub st_birthtime_nsec: c_long,
}
+ #[cfg(target_os = "netbsd")]
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct stat {
+ pub st_mode: mode_t,
+ pub st_dev: dev_t,
+ pub st_ino: ino_t,
+ pub st_nlink: nlink_t,
+ pub st_uid: uid_t,
+ pub st_gid: gid_t,
+ pub st_rdev: dev_t,
+ pub st_atime: time_t,
+ pub st_atime_nsec: c_long,
+ pub st_mtime: time_t,
+ pub st_mtime_nsec: c_long,
+ pub st_ctime: time_t,
+ pub st_ctime_nsec: c_long,
+ pub st_birthtime: time_t,
+ pub st_birthtime_nsec: c_long,
+ pub st_size: off_t,
+ pub st_blocks: blkcnt_t,
+ pub st_blksize: blksize_t,
+ pub st_flags: fflags_t,
+ pub st_gen: uint32_t,
+ st_spare: [uint32_t; 2],
+ }
+
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
+ #[cfg(not(target_os = "netbsd"))]
pub type pthread_attr_t = *mut c_void;
+ #[cfg(target_os = "netbsd")]
+ #[repr(C)]
+ #[derive(Copy, Clone)]
+ pub struct pthread_attr_t {
+ pta_magic: c_uint,
+ pta_flags: c_int,
+ pta_private: *mut c_void,
+ }
}
pub mod posix08 {
}
// pub Note: this is the struct called stat64 in Windows. Not stat,
// nor stati64.
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: u16,
// note that this is called utimbuf64 in Windows
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time64_t,
pub modtime: time64_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timeval {
+ #[derive(Copy, Clone)]
+ pub struct timeval {
pub tv_sec: c_long,
pub tv_usec: c_long,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timespec {
+ #[derive(Copy, Clone)]
+ pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_storage {
+ #[derive(Copy)]
+ pub struct sockaddr_storage {
pub ss_family: sa_family_t,
pub __ss_pad1: [u8; 6],
pub __ss_align: i64,
pub __ss_pad2: [u8; 112],
}
impl ::core::clone::Clone for sockaddr_storage {
- fn clone(&self) -> sockaddr_storage { *self }
+ fn clone(&self) -> sockaddr_storage {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
pub sin_addr: in_addr,
pub sin_zero: [u8; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in_addr {
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in6_addr {
- pub s6_addr: [u16; 8]
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u16; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct addrinfo {
+ #[derive(Copy, Clone)]
+ pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
pub ai_next: *mut addrinfo,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_un {
+ #[derive(Copy)]
+ pub struct sockaddr_un {
pub sun_family: sa_family_t,
- pub sun_path: [c_char; 108]
+ pub sun_path: [c_char; 108],
}
impl ::core::clone::Clone for sockaddr_un {
- fn clone(&self) -> sockaddr_un { *self }
+ fn clone(&self) -> sockaddr_un {
+ *self
+ }
}
}
}
pub mod bsd44 {
}
pub mod extra {
- use consts::os::extra::{MAX_PROTOCOL_CHAIN,
- WSAPROTOCOL_LEN};
+ use consts::os::extra::{MAX_PROTOCOL_CHAIN, WSAPROTOCOL_LEN};
use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, c_uint, size_t};
use types::os::arch::c95::{c_long, c_ulong};
- use types::os::arch::c95::{wchar_t};
+ use types::os::arch::c95::wchar_t;
use types::os::arch::c99::{c_ulonglong, c_longlong, uintptr_t};
pub type BOOL = c_int;
pub type LPCH = *mut CHAR;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct SECURITY_ATTRIBUTES {
+ #[derive(Copy, Clone)]
+ pub struct SECURITY_ATTRIBUTES {
pub nLength: DWORD,
pub lpSecurityDescriptor: LPVOID,
pub bInheritHandle: BOOL,
pub type int64 = i64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct STARTUPINFO {
+ #[derive(Copy, Clone)]
+ pub struct STARTUPINFO {
pub cb: DWORD,
pub lpReserved: LPWSTR,
pub lpDesktop: LPWSTR,
pub type LPSTARTUPINFO = *mut STARTUPINFO;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct PROCESS_INFORMATION {
+ #[derive(Copy, Clone)]
+ pub struct PROCESS_INFORMATION {
pub hProcess: HANDLE,
pub hThread: HANDLE,
pub dwProcessId: DWORD,
pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct SYSTEM_INFO {
+ #[derive(Copy, Clone)]
+ pub struct SYSTEM_INFO {
pub wProcessorArchitecture: WORD,
pub wReserved: WORD,
pub dwPageSize: DWORD,
pub type LPSYSTEM_INFO = *mut SYSTEM_INFO;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct MEMORY_BASIC_INFORMATION {
+ #[derive(Copy, Clone)]
+ pub struct MEMORY_BASIC_INFORMATION {
pub BaseAddress: LPVOID,
pub AllocationBase: LPVOID,
pub AllocationProtect: DWORD,
pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct OVERLAPPED {
+ #[derive(Copy, Clone)]
+ pub struct OVERLAPPED {
pub Internal: *mut c_ulong,
pub InternalHigh: *mut c_ulong,
pub Offset: DWORD,
pub type LPOVERLAPPED = *mut OVERLAPPED;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct FILETIME {
+ #[derive(Copy, Clone)]
+ pub struct FILETIME {
pub dwLowDateTime: DWORD,
pub dwHighDateTime: DWORD,
}
pub type LPFILETIME = *mut FILETIME;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct GUID {
+ #[derive(Copy, Clone)]
+ pub struct GUID {
pub Data1: DWORD,
pub Data2: WORD,
pub Data3: WORD,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct WSAPROTOCOLCHAIN {
+ #[derive(Copy, Clone)]
+ pub struct WSAPROTOCOLCHAIN {
pub ChainLen: c_int,
pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize],
}
pub type LPWSAPROTOCOLCHAIN = *mut WSAPROTOCOLCHAIN;
#[repr(C)]
- #[derive(Copy)] pub struct WSAPROTOCOL_INFO {
+ #[derive(Copy)]
+ pub struct WSAPROTOCOL_INFO {
pub dwServiceFlags1: DWORD,
pub dwServiceFlags2: DWORD,
pub dwServiceFlags3: DWORD,
pub iSecurityScheme: c_int,
pub dwMessageSize: DWORD,
pub dwProviderReserved: DWORD,
- pub szProtocol: [u8; WSAPROTOCOL_LEN as usize + 1],
+ pub szProtocol: [u8; (WSAPROTOCOL_LEN as usize) + 1],
}
impl ::core::clone::Clone for WSAPROTOCOL_INFO {
- fn clone(&self) -> WSAPROTOCOL_INFO { *self }
+ fn clone(&self) -> WSAPROTOCOL_INFO {
+ *self
+ }
}
pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
pub type GROUP = c_uint;
#[repr(C)]
- #[derive(Copy)] pub struct WIN32_FIND_DATAW {
+ #[derive(Copy)]
+ pub struct WIN32_FIND_DATAW {
pub dwFileAttributes: DWORD,
pub ftCreationTime: FILETIME,
pub ftLastAccessTime: FILETIME,
pub cAlternateFileName: [wchar_t; 14],
}
impl ::core::clone::Clone for WIN32_FIND_DATAW {
- fn clone(&self) -> WIN32_FIND_DATAW { *self }
+ fn clone(&self) -> WIN32_FIND_DATAW {
+ *self
+ }
}
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, size_t, time_t};
use types::os::arch::c95::{suseconds_t, c_long};
- use types::os::arch::c99::{uintptr_t};
+ use types::os::arch::c99::uintptr_t;
pub type pthread_t = uintptr_t;
pub type rlim_t = u64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct glob_t {
- pub gl_pathc: size_t,
+ #[derive(Copy, Clone)]
+ pub struct glob_t {
+ pub gl_pathc: size_t,
pub __unused1: c_int,
- pub gl_offs: size_t,
+ pub gl_offs: size_t,
pub __unused2: c_int,
- pub gl_pathv: *mut *mut c_char,
+ pub gl_pathv: *mut *mut c_char,
pub __unused3: *mut c_void,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timeval {
+ #[derive(Copy, Clone)]
+ pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct timespec {
+ #[derive(Copy, Clone)]
+ pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub ru_msgrcv: c_long,
pub ru_nsignals: c_long,
pub ru_nvcsw: c_long,
- pub ru_nivcsw: c_long
+ pub ru_nivcsw: c_long,
}
}
pub mod bsd44 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, c_uint};
pub type socklen_t = u32;
pub type in_port_t = u16;
pub type in_addr_t = u32;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
pub sa_len: u8,
pub sa_family: sa_family_t,
pub sa_data: [u8; 14],
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_storage {
+ #[derive(Copy)]
+ pub struct sockaddr_storage {
pub ss_len: u8,
pub ss_family: sa_family_t,
pub __ss_pad1: [u8; 6],
pub __ss_pad2: [u8; 112],
}
impl ::core::clone::Clone for sockaddr_storage {
- fn clone(&self) -> sockaddr_storage { *self }
+ fn clone(&self) -> sockaddr_storage {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
pub sin_len: u8,
pub sin_family: sa_family_t,
pub sin_port: in_port_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in_addr {
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
pub s_addr: in_addr_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct sockaddr_in6 {
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
pub sin6_len: u8,
pub sin6_family: sa_family_t,
pub sin6_port: in_port_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct in6_addr {
- pub s6_addr: [u16; 8]
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u16; 8],
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip_mreq {
pub imr_multiaddr: in_addr,
pub imr_interface: in_addr,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ip6_mreq {
+ #[derive(Copy, Clone)]
+ pub struct ip6_mreq {
pub ipv6mr_multiaddr: in6_addr,
pub ipv6mr_interface: c_uint,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct addrinfo {
+ #[derive(Copy, Clone)]
+ pub struct addrinfo {
pub ai_flags: c_int,
pub ai_family: c_int,
pub ai_socktype: c_int,
}
#[repr(C)]
- #[derive(Copy)] pub struct sockaddr_un {
+ #[derive(Copy)]
+ pub struct sockaddr_un {
pub sun_len: u8,
pub sun_family: sa_family_t,
- pub sun_path: [c_char; 104]
+ pub sun_path: [c_char; 104],
}
impl ::core::clone::Clone for sockaddr_un {
- fn clone(&self) -> sockaddr_un { *self }
+ fn clone(&self) -> sockaddr_un {
+ *self
+ }
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct ifaddrs {
+ #[derive(Copy, Clone)]
+ pub struct ifaddrs {
pub ifa_next: *mut ifaddrs,
pub ifa_name: *mut c_char,
pub ifa_flags: c_uint,
pub ifa_addr: *mut sockaddr,
pub ifa_netmask: *mut sockaddr,
pub ifa_dstaddr: *mut sockaddr,
- pub ifa_data: *mut c_void
+ pub ifa_data: *mut c_void,
}
}
}
pub mod posix01 {
use types::common::c99::{int32_t, int64_t, uint32_t};
use types::os::arch::c95::{c_char, c_long, time_t};
- use types::os::arch::posix88::{dev_t, gid_t, ino_t,
- mode_t, off_t, uid_t};
+ use types::os::arch::posix88::{dev_t, gid_t, ino_t, mode_t, off_t, uid_t};
pub type nlink_t = u16;
pub type blksize_t = i32;
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub st_mode: mode_t,
pub st_nlink: nlink_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct pthread_attr_t {
+ #[derive(Copy)]
+ pub struct pthread_attr_t {
pub __sig: c_long,
- pub __opaque: [c_char; 36]
+ pub __opaque: [c_char; 36],
}
impl ::core::clone::Clone for pthread_attr_t {
- fn clone(&self) -> pthread_attr_t { *self }
+ fn clone(&self) -> pthread_attr_t {
+ *self
+ }
}
}
pub mod posix08 {
}
pub mod extra {
#[repr(C)]
- #[derive(Copy, Clone)] pub struct mach_timebase_info {
+ #[derive(Copy, Clone)]
+ pub struct mach_timebase_info {
pub numer: u32,
pub denom: u32,
}
}
pub mod posix01 {
use types::common::c99::{int32_t, int64_t};
- use types::common::c99::{uint32_t};
+ use types::common::c99::uint32_t;
use types::os::arch::c95::{c_char, c_long, time_t};
use types::os::arch::posix88::{dev_t, gid_t, ino_t};
use types::os::arch::posix88::{mode_t, off_t, uid_t};
pub type blkcnt_t = i64;
#[repr(C)]
- #[derive(Copy, Clone)] pub struct stat {
+ #[derive(Copy, Clone)]
+ pub struct stat {
pub st_dev: dev_t,
pub st_mode: mode_t,
pub st_nlink: nlink_t,
}
#[repr(C)]
- #[derive(Copy, Clone)] pub struct utimbuf {
+ #[derive(Copy, Clone)]
+ pub struct utimbuf {
pub actime: time_t,
pub modtime: time_t,
}
#[repr(C)]
- #[derive(Copy)] pub struct pthread_attr_t {
+ #[derive(Copy)]
+ pub struct pthread_attr_t {
pub __sig: c_long,
- pub __opaque: [c_char; 56]
+ pub __opaque: [c_char; 56],
}
impl ::core::clone::Clone for pthread_attr_t {
- fn clone(&self) -> pthread_attr_t { *self }
+ fn clone(&self) -> pthread_attr_t {
+ *self
+ }
}
}
pub mod posix08 {
}
pub mod extra {
#[repr(C)]
- #[derive(Copy, Clone)] pub struct mach_timebase_info {
+ #[derive(Copy, Clone)]
+ pub struct mach_timebase_info {
pub numer: u32,
pub denom: u32,
}
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
- pub const EXIT_FAILURE : c_int = 1;
- pub const EXIT_SUCCESS : c_int = 0;
- pub const RAND_MAX : c_int = 32767;
- pub const EOF : c_int = -1;
- pub const SEEK_SET : c_int = 0;
- pub const SEEK_CUR : c_int = 1;
- pub const SEEK_END : c_int = 2;
- pub const _IOFBF : c_int = 0;
- pub const _IONBF : c_int = 4;
- pub const _IOLBF : c_int = 64;
- pub const BUFSIZ : c_uint = 512;
- pub const FOPEN_MAX : c_uint = 20;
- pub const FILENAME_MAX : c_uint = 260;
- pub const L_tmpnam : c_uint = 16;
- pub const TMP_MAX : c_uint = 32767;
+ pub const EXIT_FAILURE: c_int = 1;
+ pub const EXIT_SUCCESS: c_int = 0;
+ pub const RAND_MAX: c_int = 32767;
+ pub const EOF: c_int = -1;
+ pub const SEEK_SET: c_int = 0;
+ pub const SEEK_CUR: c_int = 1;
+ pub const SEEK_END: c_int = 2;
+ pub const _IOFBF: c_int = 0;
+ pub const _IONBF: c_int = 4;
+ pub const _IOLBF: c_int = 64;
+ pub const BUFSIZ: c_uint = 512;
+ pub const FOPEN_MAX: c_uint = 20;
+ pub const FILENAME_MAX: c_uint = 260;
+ pub const L_tmpnam: c_uint = 16;
+ pub const TMP_MAX: c_uint = 32767;
pub const WSAEINTR: c_int = 10004;
pub const WSAEBADF: c_int = 10009;
use types::os::arch::c95::c_int;
use types::os::arch::posix88::mode_t;
- pub const O_RDONLY : c_int = 0;
- pub const O_WRONLY : c_int = 1;
- pub const O_RDWR : c_int = 2;
- pub const O_APPEND : c_int = 8;
- pub const O_CREAT : c_int = 256;
- pub const O_EXCL : c_int = 1024;
- pub const O_TRUNC : c_int = 512;
- pub const S_IFIFO : c_int = 4096;
- pub const S_IFCHR : c_int = 8192;
- pub const S_IFBLK : c_int = 12288;
- pub const S_IFDIR : c_int = 16384;
- pub const S_IFREG : c_int = 32768;
- pub const S_IFLNK : c_int = 40960;
- pub const S_IFSOCK : mode_t = 49152;
- pub const S_IFMT : c_int = 61440;
- pub const S_IEXEC : c_int = 64;
- pub const S_IWRITE : c_int = 128;
- pub const S_IREAD : c_int = 256;
- pub const S_IRWXU : c_int = 448;
- pub const S_IXUSR : c_int = 64;
- pub const S_IWUSR : c_int = 128;
- pub const S_IRUSR : c_int = 256;
- pub const S_IRWXG : mode_t = 56;
- pub const S_IXGRP : mode_t = 8;
- pub const S_IWGRP : mode_t = 16;
- pub const S_IRGRP : mode_t = 32;
- pub const S_IRWXO : mode_t = 7;
- pub const S_IXOTH : mode_t = 1;
- pub const S_IWOTH : mode_t = 2;
- pub const S_IROTH : mode_t = 4;
- pub const F_OK : c_int = 0;
- pub const R_OK : c_int = 4;
- pub const W_OK : c_int = 2;
- pub const X_OK : c_int = 1;
- pub const STDIN_FILENO : c_int = 0;
- pub const STDOUT_FILENO : c_int = 1;
- pub const STDERR_FILENO : c_int = 2;
+ pub const O_RDONLY: c_int = 0;
+ pub const O_WRONLY: c_int = 1;
+ pub const O_RDWR: c_int = 2;
+ pub const O_APPEND: c_int = 8;
+ pub const O_CREAT: c_int = 256;
+ pub const O_EXCL: c_int = 1024;
+ pub const O_TRUNC: c_int = 512;
+ pub const S_IFIFO: c_int = 4096;
+ pub const S_IFCHR: c_int = 8192;
+ pub const S_IFBLK: c_int = 12288;
+ pub const S_IFDIR: c_int = 16384;
+ pub const S_IFREG: c_int = 32768;
+ pub const S_IFLNK: c_int = 40960;
+ pub const S_IFSOCK: mode_t = 49152;
+ pub const S_IFMT: c_int = 61440;
+ pub const S_IEXEC: c_int = 64;
+ pub const S_IWRITE: c_int = 128;
+ pub const S_IREAD: c_int = 256;
+ pub const S_IRWXU: c_int = 448;
+ pub const S_IXUSR: c_int = 64;
+ pub const S_IWUSR: c_int = 128;
+ pub const S_IRUSR: c_int = 256;
+ pub const S_IRWXG: mode_t = 56;
+ pub const S_IXGRP: mode_t = 8;
+ pub const S_IWGRP: mode_t = 16;
+ pub const S_IRGRP: mode_t = 32;
+ pub const S_IRWXO: mode_t = 7;
+ pub const S_IXOTH: mode_t = 1;
+ pub const S_IWOTH: mode_t = 2;
+ pub const S_IROTH: mode_t = 4;
+ pub const F_OK: c_int = 0;
+ pub const R_OK: c_int = 4;
+ pub const W_OK: c_int = 2;
+ pub const X_OK: c_int = 1;
+ pub const STDIN_FILENO: c_int = 0;
+ pub const STDOUT_FILENO: c_int = 1;
+ pub const STDERR_FILENO: c_int = 2;
}
pub mod posix01 {
}
use types::os::arch::c95::{c_int, c_long};
use types::os::arch::extra::{WORD, DWORD, BOOL, HANDLE};
- pub const TRUE : BOOL = 1;
- pub const FALSE : BOOL = 0;
+ pub const TRUE: BOOL = 1;
+ pub const FALSE: BOOL = 0;
- pub const O_TEXT : c_int = 16384;
- pub const O_BINARY : c_int = 32768;
+ pub const O_TEXT: c_int = 16384;
+ pub const O_BINARY: c_int = 32768;
pub const O_NOINHERIT: c_int = 128;
- pub const ERROR_SUCCESS : c_int = 0;
+ pub const ERROR_SUCCESS: c_int = 0;
pub const ERROR_INVALID_FUNCTION: c_int = 1;
pub const ERROR_FILE_NOT_FOUND: c_int = 2;
pub const ERROR_ACCESS_DENIED: c_int = 5;
- pub const ERROR_INVALID_HANDLE : c_int = 6;
+ pub const ERROR_INVALID_HANDLE: c_int = 6;
pub const ERROR_BROKEN_PIPE: c_int = 109;
- pub const ERROR_DISK_FULL : c_int = 112;
- pub const ERROR_CALL_NOT_IMPLEMENTED : c_int = 120;
- pub const ERROR_INSUFFICIENT_BUFFER : c_int = 122;
- pub const ERROR_INVALID_NAME : c_int = 123;
- pub const ERROR_ALREADY_EXISTS : c_int = 183;
+ pub const ERROR_DISK_FULL: c_int = 112;
+ pub const ERROR_CALL_NOT_IMPLEMENTED: c_int = 120;
+ pub const ERROR_INSUFFICIENT_BUFFER: c_int = 122;
+ pub const ERROR_INVALID_NAME: c_int = 123;
+ pub const ERROR_ALREADY_EXISTS: c_int = 183;
pub const ERROR_PIPE_BUSY: c_int = 231;
pub const ERROR_NO_DATA: c_int = 232;
- pub const ERROR_INVALID_ADDRESS : c_int = 487;
+ pub const ERROR_INVALID_ADDRESS: c_int = 487;
pub const ERROR_PIPE_CONNECTED: c_int = 535;
pub const ERROR_NOTHING_TO_TERMINATE: c_int = 758;
pub const ERROR_OPERATION_ABORTED: c_int = 995;
pub const ERROR_IO_PENDING: c_int = 997;
- pub const ERROR_FILE_INVALID : c_int = 1006;
+ pub const ERROR_FILE_INVALID: c_int = 1006;
pub const ERROR_NOT_FOUND: c_int = 1168;
pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE;
- pub const DELETE : DWORD = 0x00010000;
- pub const READ_CONTROL : DWORD = 0x00020000;
- pub const SYNCHRONIZE : DWORD = 0x00100000;
- pub const WRITE_DAC : DWORD = 0x00040000;
- pub const WRITE_OWNER : DWORD = 0x00080000;
-
- pub const PROCESS_CREATE_PROCESS : DWORD = 0x0080;
- pub const PROCESS_CREATE_THREAD : DWORD = 0x0002;
- pub const PROCESS_DUP_HANDLE : DWORD = 0x0040;
- pub const PROCESS_QUERY_INFORMATION : DWORD = 0x0400;
- pub const PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000;
- pub const PROCESS_SET_INFORMATION : DWORD = 0x0200;
- pub const PROCESS_SET_QUOTA : DWORD = 0x0100;
- pub const PROCESS_SUSPEND_RESUME : DWORD = 0x0800;
- pub const PROCESS_TERMINATE : DWORD = 0x0001;
- pub const PROCESS_VM_OPERATION : DWORD = 0x0008;
- pub const PROCESS_VM_READ : DWORD = 0x0010;
- pub const PROCESS_VM_WRITE : DWORD = 0x0020;
-
- pub const STARTF_FORCEONFEEDBACK : DWORD = 0x00000040;
- pub const STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080;
- pub const STARTF_PREVENTPINNING : DWORD = 0x00002000;
- pub const STARTF_RUNFULLSCREEN : DWORD = 0x00000020;
- pub const STARTF_TITLEISAPPID : DWORD = 0x00001000;
- pub const STARTF_TITLEISLINKNAME : DWORD = 0x00000800;
- pub const STARTF_USECOUNTCHARS : DWORD = 0x00000008;
- pub const STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010;
- pub const STARTF_USEHOTKEY : DWORD = 0x00000200;
- pub const STARTF_USEPOSITION : DWORD = 0x00000004;
- pub const STARTF_USESHOWWINDOW : DWORD = 0x00000001;
- pub const STARTF_USESIZE : DWORD = 0x00000002;
- pub const STARTF_USESTDHANDLES : DWORD = 0x00000100;
-
- pub const WAIT_ABANDONED : DWORD = 0x00000080;
- pub const WAIT_OBJECT_0 : DWORD = 0x00000000;
- pub const WAIT_TIMEOUT : DWORD = 0x00000102;
- pub const WAIT_FAILED : DWORD = !0;
-
- pub const DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001;
- pub const DUPLICATE_SAME_ACCESS : DWORD = 0x00000002;
-
- pub const INFINITE : DWORD = !0;
- pub const STILL_ACTIVE : DWORD = 259;
-
- pub const MEM_COMMIT : DWORD = 0x00001000;
- pub const MEM_RESERVE : DWORD = 0x00002000;
- pub const MEM_DECOMMIT : DWORD = 0x00004000;
- pub const MEM_RELEASE : DWORD = 0x00008000;
- pub const MEM_RESET : DWORD = 0x00080000;
- pub const MEM_RESET_UNDO : DWORD = 0x1000000;
- pub const MEM_LARGE_PAGES : DWORD = 0x20000000;
- pub const MEM_PHYSICAL : DWORD = 0x00400000;
- pub const MEM_TOP_DOWN : DWORD = 0x00100000;
- pub const MEM_WRITE_WATCH : DWORD = 0x00200000;
-
- pub const PAGE_EXECUTE : DWORD = 0x10;
- pub const PAGE_EXECUTE_READ : DWORD = 0x20;
- pub const PAGE_EXECUTE_READWRITE : DWORD = 0x40;
- pub const PAGE_EXECUTE_WRITECOPY : DWORD = 0x80;
- pub const PAGE_NOACCESS : DWORD = 0x01;
- pub const PAGE_READONLY : DWORD = 0x02;
- pub const PAGE_READWRITE : DWORD = 0x04;
- pub const PAGE_WRITECOPY : DWORD = 0x08;
- pub const PAGE_GUARD : DWORD = 0x100;
- pub const PAGE_NOCACHE : DWORD = 0x200;
- pub const PAGE_WRITECOMBINE : DWORD = 0x400;
-
- pub const SEC_COMMIT : DWORD = 0x8000000;
- pub const SEC_IMAGE : DWORD = 0x1000000;
- pub const SEC_IMAGE_NO_EXECUTE : DWORD = 0x11000000;
- pub const SEC_LARGE_PAGES : DWORD = 0x80000000;
- pub const SEC_NOCACHE : DWORD = 0x10000000;
- pub const SEC_RESERVE : DWORD = 0x4000000;
- pub const SEC_WRITECOMBINE : DWORD = 0x40000000;
-
- pub const FILE_MAP_ALL_ACCESS : DWORD = 0xf001f;
- pub const FILE_MAP_READ : DWORD = 0x4;
- pub const FILE_MAP_WRITE : DWORD = 0x2;
- pub const FILE_MAP_COPY : DWORD = 0x1;
- pub const FILE_MAP_EXECUTE : DWORD = 0x20;
-
- pub const PROCESSOR_ARCHITECTURE_INTEL : WORD = 0;
- pub const PROCESSOR_ARCHITECTURE_ARM : WORD = 5;
- pub const PROCESSOR_ARCHITECTURE_IA64 : WORD = 6;
- pub const PROCESSOR_ARCHITECTURE_AMD64 : WORD = 9;
- pub const PROCESSOR_ARCHITECTURE_UNKNOWN : WORD = 0xffff;
+ pub const DELETE: DWORD = 0x00010000;
+ pub const READ_CONTROL: DWORD = 0x00020000;
+ pub const SYNCHRONIZE: DWORD = 0x00100000;
+ pub const WRITE_DAC: DWORD = 0x00040000;
+ pub const WRITE_OWNER: DWORD = 0x00080000;
+
+ pub const PROCESS_CREATE_PROCESS: DWORD = 0x0080;
+ pub const PROCESS_CREATE_THREAD: DWORD = 0x0002;
+ pub const PROCESS_DUP_HANDLE: DWORD = 0x0040;
+ pub const PROCESS_QUERY_INFORMATION: DWORD = 0x0400;
+ pub const PROCESS_QUERY_LIMITED_INFORMATION: DWORD = 0x1000;
+ pub const PROCESS_SET_INFORMATION: DWORD = 0x0200;
+ pub const PROCESS_SET_QUOTA: DWORD = 0x0100;
+ pub const PROCESS_SUSPEND_RESUME: DWORD = 0x0800;
+ pub const PROCESS_TERMINATE: DWORD = 0x0001;
+ pub const PROCESS_VM_OPERATION: DWORD = 0x0008;
+ pub const PROCESS_VM_READ: DWORD = 0x0010;
+ pub const PROCESS_VM_WRITE: DWORD = 0x0020;
+
+ pub const STARTF_FORCEONFEEDBACK: DWORD = 0x00000040;
+ pub const STARTF_FORCEOFFFEEDBACK: DWORD = 0x00000080;
+ pub const STARTF_PREVENTPINNING: DWORD = 0x00002000;
+ pub const STARTF_RUNFULLSCREEN: DWORD = 0x00000020;
+ pub const STARTF_TITLEISAPPID: DWORD = 0x00001000;
+ pub const STARTF_TITLEISLINKNAME: DWORD = 0x00000800;
+ pub const STARTF_USECOUNTCHARS: DWORD = 0x00000008;
+ pub const STARTF_USEFILLATTRIBUTE: DWORD = 0x00000010;
+ pub const STARTF_USEHOTKEY: DWORD = 0x00000200;
+ pub const STARTF_USEPOSITION: DWORD = 0x00000004;
+ pub const STARTF_USESHOWWINDOW: DWORD = 0x00000001;
+ pub const STARTF_USESIZE: DWORD = 0x00000002;
+ pub const STARTF_USESTDHANDLES: DWORD = 0x00000100;
+
+ pub const WAIT_ABANDONED: DWORD = 0x00000080;
+ pub const WAIT_OBJECT_0: DWORD = 0x00000000;
+ pub const WAIT_TIMEOUT: DWORD = 0x00000102;
+ pub const WAIT_FAILED: DWORD = !0;
+
+ pub const DUPLICATE_CLOSE_SOURCE: DWORD = 0x00000001;
+ pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002;
+
+ pub const INFINITE: DWORD = !0;
+ pub const STILL_ACTIVE: DWORD = 259;
+
+ pub const MEM_COMMIT: DWORD = 0x00001000;
+ pub const MEM_RESERVE: DWORD = 0x00002000;
+ pub const MEM_DECOMMIT: DWORD = 0x00004000;
+ pub const MEM_RELEASE: DWORD = 0x00008000;
+ pub const MEM_RESET: DWORD = 0x00080000;
+ pub const MEM_RESET_UNDO: DWORD = 0x1000000;
+ pub const MEM_LARGE_PAGES: DWORD = 0x20000000;
+ pub const MEM_PHYSICAL: DWORD = 0x00400000;
+ pub const MEM_TOP_DOWN: DWORD = 0x00100000;
+ pub const MEM_WRITE_WATCH: DWORD = 0x00200000;
+
+ pub const PAGE_EXECUTE: DWORD = 0x10;
+ pub const PAGE_EXECUTE_READ: DWORD = 0x20;
+ pub const PAGE_EXECUTE_READWRITE: DWORD = 0x40;
+ pub const PAGE_EXECUTE_WRITECOPY: DWORD = 0x80;
+ pub const PAGE_NOACCESS: DWORD = 0x01;
+ pub const PAGE_READONLY: DWORD = 0x02;
+ pub const PAGE_READWRITE: DWORD = 0x04;
+ pub const PAGE_WRITECOPY: DWORD = 0x08;
+ pub const PAGE_GUARD: DWORD = 0x100;
+ pub const PAGE_NOCACHE: DWORD = 0x200;
+ pub const PAGE_WRITECOMBINE: DWORD = 0x400;
+
+ pub const SEC_COMMIT: DWORD = 0x8000000;
+ pub const SEC_IMAGE: DWORD = 0x1000000;
+ pub const SEC_IMAGE_NO_EXECUTE: DWORD = 0x11000000;
+ pub const SEC_LARGE_PAGES: DWORD = 0x80000000;
+ pub const SEC_NOCACHE: DWORD = 0x10000000;
+ pub const SEC_RESERVE: DWORD = 0x4000000;
+ pub const SEC_WRITECOMBINE: DWORD = 0x40000000;
+
+ pub const FILE_MAP_ALL_ACCESS: DWORD = 0xf001f;
+ pub const FILE_MAP_READ: DWORD = 0x4;
+ pub const FILE_MAP_WRITE: DWORD = 0x2;
+ pub const FILE_MAP_COPY: DWORD = 0x1;
+ pub const FILE_MAP_EXECUTE: DWORD = 0x20;
+
+ pub const PROCESSOR_ARCHITECTURE_INTEL: WORD = 0;
+ pub const PROCESSOR_ARCHITECTURE_ARM: WORD = 5;
+ pub const PROCESSOR_ARCHITECTURE_IA64: WORD = 6;
+ pub const PROCESSOR_ARCHITECTURE_AMD64: WORD = 9;
+ pub const PROCESSOR_ARCHITECTURE_UNKNOWN: WORD = 0xffff;
pub const MOVEFILE_COPY_ALLOWED: DWORD = 2;
pub const MOVEFILE_CREATE_HARDLINK: DWORD = 16;
pub const STANDARD_RIGHTS_WRITE: DWORD = 0x20000;
pub const FILE_WRITE_EA: DWORD = 0x00000010;
pub const FILE_READ_EA: DWORD = 0x00000008;
- pub const FILE_GENERIC_READ: DWORD =
- STANDARD_RIGHTS_READ | FILE_READ_DATA |
- FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE;
- pub const FILE_GENERIC_WRITE: DWORD =
- STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA |
- FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA |
- SYNCHRONIZE;
+ pub const FILE_GENERIC_READ: DWORD = STANDARD_RIGHTS_READ | FILE_READ_DATA |
+ FILE_READ_ATTRIBUTES |
+ FILE_READ_EA |
+ SYNCHRONIZE;
+ pub const FILE_GENERIC_WRITE: DWORD = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA |
+ FILE_WRITE_ATTRIBUTES |
+ FILE_WRITE_EA |
+ FILE_APPEND_DATA |
+ SYNCHRONIZE;
pub const FILE_BEGIN: DWORD = 0;
pub const FILE_CURRENT: DWORD = 1;
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
- pub const EXIT_FAILURE : c_int = 1;
- pub const EXIT_SUCCESS : c_int = 0;
- pub const RAND_MAX : c_int = 2147483647;
- pub const EOF : c_int = -1;
- pub const SEEK_SET : c_int = 0;
- pub const SEEK_CUR : c_int = 1;
- pub const SEEK_END : c_int = 2;
- pub const _IOFBF : c_int = 0;
- pub const _IONBF : c_int = 2;
- pub const _IOLBF : c_int = 1;
- pub const BUFSIZ : c_uint = 8192;
- pub const FOPEN_MAX : c_uint = 16;
- pub const FILENAME_MAX : c_uint = 4096;
- pub const L_tmpnam : c_uint = 20;
- pub const TMP_MAX : c_uint = 238328;
+ pub const EXIT_FAILURE: c_int = 1;
+ pub const EXIT_SUCCESS: c_int = 0;
+ pub const RAND_MAX: c_int = 2147483647;
+ pub const EOF: c_int = -1;
+ pub const SEEK_SET: c_int = 0;
+ pub const SEEK_CUR: c_int = 1;
+ pub const SEEK_END: c_int = 2;
+ pub const _IOFBF: c_int = 0;
+ pub const _IONBF: c_int = 2;
+ pub const _IOLBF: c_int = 1;
+ pub const BUFSIZ: c_uint = 8192;
+ pub const FOPEN_MAX: c_uint = 16;
+ pub const FILENAME_MAX: c_uint = 4096;
+ pub const L_tmpnam: c_uint = 20;
+ pub const TMP_MAX: c_uint = 238328;
}
pub mod c99 {
}
use types::common::c95::c_void;
use types::os::arch::posix88::mode_t;
- pub const O_RDONLY : c_int = 0;
- pub const O_WRONLY : c_int = 1;
- pub const O_RDWR : c_int = 2;
- pub const O_APPEND : c_int = 1024;
- pub const O_CREAT : c_int = 64;
- pub const O_EXCL : c_int = 128;
- pub const O_NOCTTY : c_int = 256;
- pub const O_TRUNC : c_int = 512;
- pub const S_IFIFO : mode_t = 4096;
- pub const S_IFCHR : mode_t = 8192;
- pub const S_IFBLK : mode_t = 24576;
- pub const S_IFDIR : mode_t = 16384;
- pub const S_IFREG : mode_t = 32768;
- pub const S_IFLNK : mode_t = 40960;
- pub const S_IFSOCK : mode_t = 49152;
- pub const S_IFMT : mode_t = 61440;
- pub const S_IEXEC : mode_t = 64;
- pub const S_IWRITE : mode_t = 128;
- pub const S_IREAD : mode_t = 256;
- pub const S_IRWXU : mode_t = 448;
- pub const S_IXUSR : mode_t = 64;
- pub const S_IWUSR : mode_t = 128;
- pub const S_IRUSR : mode_t = 256;
- pub const S_IRWXG : mode_t = 56;
- pub const S_IXGRP : mode_t = 8;
- pub const S_IWGRP : mode_t = 16;
- pub const S_IRGRP : mode_t = 32;
- pub const S_IRWXO : mode_t = 7;
- pub const S_IXOTH : mode_t = 1;
- pub const S_IWOTH : mode_t = 2;
- pub const S_IROTH : mode_t = 4;
- pub const F_OK : c_int = 0;
- pub const R_OK : c_int = 4;
- pub const W_OK : c_int = 2;
- pub const X_OK : c_int = 1;
- pub const STDIN_FILENO : c_int = 0;
- pub const STDOUT_FILENO : c_int = 1;
- pub const STDERR_FILENO : c_int = 2;
- pub const F_LOCK : c_int = 1;
- pub const F_TEST : c_int = 3;
- pub const F_TLOCK : c_int = 2;
- pub const F_ULOCK : c_int = 0;
- pub const SIGHUP : c_int = 1;
- pub const SIGINT : c_int = 2;
- pub const SIGQUIT : c_int = 3;
- pub const SIGILL : c_int = 4;
- pub const SIGABRT : c_int = 6;
- pub const SIGFPE : c_int = 8;
- pub const SIGKILL : c_int = 9;
- pub const SIGSEGV : c_int = 11;
- pub const SIGPIPE : c_int = 13;
- pub const SIGALRM : c_int = 14;
- pub const SIGTERM : c_int = 15;
-
- pub const PROT_NONE : c_int = 0;
- pub const PROT_READ : c_int = 1;
- pub const PROT_WRITE : c_int = 2;
- pub const PROT_EXEC : c_int = 4;
-
- pub const MAP_FILE : c_int = 0x0000;
- pub const MAP_SHARED : c_int = 0x0001;
- pub const MAP_PRIVATE : c_int = 0x0002;
- pub const MAP_FIXED : c_int = 0x0010;
- pub const MAP_ANON : c_int = 0x0020;
-
- pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
-
- pub const MCL_CURRENT : c_int = 0x0001;
- pub const MCL_FUTURE : c_int = 0x0002;
-
- pub const MS_ASYNC : c_int = 0x0001;
- pub const MS_INVALIDATE : c_int = 0x0002;
- pub const MS_SYNC : c_int = 0x0004;
-
- pub const EPERM : c_int = 1;
- pub const ENOENT : c_int = 2;
- pub const ESRCH : c_int = 3;
- pub const EINTR : c_int = 4;
- pub const EIO : c_int = 5;
- pub const ENXIO : c_int = 6;
- pub const E2BIG : c_int = 7;
- pub const ENOEXEC : c_int = 8;
- pub const EBADF : c_int = 9;
- pub const ECHILD : c_int = 10;
- pub const EAGAIN : c_int = 11;
- pub const ENOMEM : c_int = 12;
- pub const EACCES : c_int = 13;
- pub const EFAULT : c_int = 14;
- pub const ENOTBLK : c_int = 15;
- pub const EBUSY : c_int = 16;
- pub const EEXIST : c_int = 17;
- pub const EXDEV : c_int = 18;
- pub const ENODEV : c_int = 19;
- pub const ENOTDIR : c_int = 20;
- pub const EISDIR : c_int = 21;
- pub const EINVAL : c_int = 22;
- pub const ENFILE : c_int = 23;
- pub const EMFILE : c_int = 24;
- pub const ENOTTY : c_int = 25;
- pub const ETXTBSY : c_int = 26;
- pub const EFBIG : c_int = 27;
- pub const ENOSPC : c_int = 28;
- pub const ESPIPE : c_int = 29;
- pub const EROFS : c_int = 30;
- pub const EMLINK : c_int = 31;
- pub const EPIPE : c_int = 32;
- pub const EDOM : c_int = 33;
- pub const ERANGE : c_int = 34;
+ pub const O_RDONLY: c_int = 0;
+ pub const O_WRONLY: c_int = 1;
+ pub const O_RDWR: c_int = 2;
+ pub const O_APPEND: c_int = 1024;
+ pub const O_CREAT: c_int = 64;
+ pub const O_EXCL: c_int = 128;
+ pub const O_NOCTTY: c_int = 256;
+ pub const O_TRUNC: c_int = 512;
+ pub const S_IFIFO: mode_t = 4096;
+ pub const S_IFCHR: mode_t = 8192;
+ pub const S_IFBLK: mode_t = 24576;
+ pub const S_IFDIR: mode_t = 16384;
+ pub const S_IFREG: mode_t = 32768;
+ pub const S_IFLNK: mode_t = 40960;
+ pub const S_IFSOCK: mode_t = 49152;
+ pub const S_IFMT: mode_t = 61440;
+ pub const S_IEXEC: mode_t = 64;
+ pub const S_IWRITE: mode_t = 128;
+ pub const S_IREAD: mode_t = 256;
+ pub const S_IRWXU: mode_t = 448;
+ pub const S_IXUSR: mode_t = 64;
+ pub const S_IWUSR: mode_t = 128;
+ pub const S_IRUSR: mode_t = 256;
+ pub const S_IRWXG: mode_t = 56;
+ pub const S_IXGRP: mode_t = 8;
+ pub const S_IWGRP: mode_t = 16;
+ pub const S_IRGRP: mode_t = 32;
+ pub const S_IRWXO: mode_t = 7;
+ pub const S_IXOTH: mode_t = 1;
+ pub const S_IWOTH: mode_t = 2;
+ pub const S_IROTH: mode_t = 4;
+ pub const F_OK: c_int = 0;
+ pub const R_OK: c_int = 4;
+ pub const W_OK: c_int = 2;
+ pub const X_OK: c_int = 1;
+ pub const STDIN_FILENO: c_int = 0;
+ pub const STDOUT_FILENO: c_int = 1;
+ pub const STDERR_FILENO: c_int = 2;
+ pub const F_LOCK: c_int = 1;
+ pub const F_TEST: c_int = 3;
+ pub const F_TLOCK: c_int = 2;
+ pub const F_ULOCK: c_int = 0;
+ pub const SIGHUP: c_int = 1;
+ pub const SIGINT: c_int = 2;
+ pub const SIGQUIT: c_int = 3;
+ pub const SIGILL: c_int = 4;
+ pub const SIGABRT: c_int = 6;
+ pub const SIGFPE: c_int = 8;
+ pub const SIGKILL: c_int = 9;
+ pub const SIGSEGV: c_int = 11;
+ pub const SIGPIPE: c_int = 13;
+ pub const SIGALRM: c_int = 14;
+ pub const SIGTERM: c_int = 15;
+
+ pub const PROT_NONE: c_int = 0;
+ pub const PROT_READ: c_int = 1;
+ pub const PROT_WRITE: c_int = 2;
+ pub const PROT_EXEC: c_int = 4;
+
+ pub const MAP_FILE: c_int = 0x0000;
+ pub const MAP_SHARED: c_int = 0x0001;
+ pub const MAP_PRIVATE: c_int = 0x0002;
+ pub const MAP_FIXED: c_int = 0x0010;
+ pub const MAP_ANON: c_int = 0x0020;
+
+ pub const MAP_FAILED: *mut c_void = !0 as *mut c_void;
+
+ pub const MCL_CURRENT: c_int = 0x0001;
+ pub const MCL_FUTURE: c_int = 0x0002;
+
+ pub const MS_ASYNC: c_int = 0x0001;
+ pub const MS_INVALIDATE: c_int = 0x0002;
+ pub const MS_SYNC: c_int = 0x0004;
+
+ pub const EPERM: c_int = 1;
+ pub const ENOENT: c_int = 2;
+ pub const ESRCH: c_int = 3;
+ pub const EINTR: c_int = 4;
+ pub const EIO: c_int = 5;
+ pub const ENXIO: c_int = 6;
+ pub const E2BIG: c_int = 7;
+ pub const ENOEXEC: c_int = 8;
+ pub const EBADF: c_int = 9;
+ pub const ECHILD: c_int = 10;
+ pub const EAGAIN: c_int = 11;
+ pub const ENOMEM: c_int = 12;
+ pub const EACCES: c_int = 13;
+ pub const EFAULT: c_int = 14;
+ pub const ENOTBLK: c_int = 15;
+ pub const EBUSY: c_int = 16;
+ pub const EEXIST: c_int = 17;
+ pub const EXDEV: c_int = 18;
+ pub const ENODEV: c_int = 19;
+ pub const ENOTDIR: c_int = 20;
+ pub const EISDIR: c_int = 21;
+ pub const EINVAL: c_int = 22;
+ pub const ENFILE: c_int = 23;
+ pub const EMFILE: c_int = 24;
+ pub const ENOTTY: c_int = 25;
+ pub const ETXTBSY: c_int = 26;
+ pub const EFBIG: c_int = 27;
+ pub const ENOSPC: c_int = 28;
+ pub const ESPIPE: c_int = 29;
+ pub const EROFS: c_int = 30;
+ pub const EMLINK: c_int = 31;
+ pub const EPIPE: c_int = 32;
+ pub const EDOM: c_int = 33;
+ pub const ERANGE: c_int = 34;
pub const EDEADLK: c_int = 35;
pub const ENAMETOOLONG: c_int = 36;
use types::common::c95::c_void;
use types::os::arch::posix88::mode_t;
- pub const O_RDONLY : c_int = 0;
- pub const O_WRONLY : c_int = 1;
- pub const O_RDWR : c_int = 2;
- pub const O_APPEND : c_int = 8;
- pub const O_CREAT : c_int = 256;
- pub const O_EXCL : c_int = 1024;
- pub const O_NOCTTY : c_int = 2048;
- pub const O_TRUNC : c_int = 512;
- pub const S_IFIFO : mode_t = 4096;
- pub const S_IFCHR : mode_t = 8192;
- pub const S_IFBLK : mode_t = 24576;
- pub const S_IFDIR : mode_t = 16384;
- pub const S_IFREG : mode_t = 32768;
- pub const S_IFLNK : mode_t = 40960;
- pub const S_IFSOCK : mode_t = 49152;
- pub const S_IFMT : mode_t = 61440;
- pub const S_IEXEC : mode_t = 64;
- pub const S_IWRITE : mode_t = 128;
- pub const S_IREAD : mode_t = 256;
- pub const S_IRWXU : mode_t = 448;
- pub const S_IXUSR : mode_t = 64;
- pub const S_IWUSR : mode_t = 128;
- pub const S_IRUSR : mode_t = 256;
- pub const S_IRWXG : mode_t = 56;
- pub const S_IXGRP : mode_t = 8;
- pub const S_IWGRP : mode_t = 16;
- pub const S_IRGRP : mode_t = 32;
- pub const S_IRWXO : mode_t = 7;
- pub const S_IXOTH : mode_t = 1;
- pub const S_IWOTH : mode_t = 2;
- pub const S_IROTH : mode_t = 4;
- pub const F_OK : c_int = 0;
- pub const R_OK : c_int = 4;
- pub const W_OK : c_int = 2;
- pub const X_OK : c_int = 1;
- pub const STDIN_FILENO : c_int = 0;
- pub const STDOUT_FILENO : c_int = 1;
- pub const STDERR_FILENO : c_int = 2;
- pub const F_LOCK : c_int = 1;
- pub const F_TEST : c_int = 3;
- pub const F_TLOCK : c_int = 2;
- pub const F_ULOCK : c_int = 0;
- pub const SIGHUP : c_int = 1;
- pub const SIGINT : c_int = 2;
- pub const SIGQUIT : c_int = 3;
- pub const SIGILL : c_int = 4;
- pub const SIGABRT : c_int = 6;
- pub const SIGFPE : c_int = 8;
- pub const SIGKILL : c_int = 9;
- pub const SIGSEGV : c_int = 11;
- pub const SIGPIPE : c_int = 13;
- pub const SIGALRM : c_int = 14;
- pub const SIGTERM : c_int = 15;
-
- pub const PROT_NONE : c_int = 0;
- pub const PROT_READ : c_int = 1;
- pub const PROT_WRITE : c_int = 2;
- pub const PROT_EXEC : c_int = 4;
-
- pub const MAP_FILE : c_int = 0x0000;
- pub const MAP_SHARED : c_int = 0x0001;
- pub const MAP_PRIVATE : c_int = 0x0002;
- pub const MAP_FIXED : c_int = 0x0010;
- pub const MAP_ANON : c_int = 0x0800;
-
- pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
-
- pub const MCL_CURRENT : c_int = 0x0001;
- pub const MCL_FUTURE : c_int = 0x0002;
-
- pub const MS_ASYNC : c_int = 0x0001;
- pub const MS_INVALIDATE : c_int = 0x0002;
- pub const MS_SYNC : c_int = 0x0004;
-
- pub const EPERM : c_int = 1;
- pub const ENOENT : c_int = 2;
- pub const ESRCH : c_int = 3;
- pub const EINTR : c_int = 4;
- pub const EIO : c_int = 5;
- pub const ENXIO : c_int = 6;
- pub const E2BIG : c_int = 7;
- pub const ENOEXEC : c_int = 8;
- pub const EBADF : c_int = 9;
- pub const ECHILD : c_int = 10;
- pub const EAGAIN : c_int = 11;
- pub const ENOMEM : c_int = 12;
- pub const EACCES : c_int = 13;
- pub const EFAULT : c_int = 14;
- pub const ENOTBLK : c_int = 15;
- pub const EBUSY : c_int = 16;
- pub const EEXIST : c_int = 17;
- pub const EXDEV : c_int = 18;
- pub const ENODEV : c_int = 19;
- pub const ENOTDIR : c_int = 20;
- pub const EISDIR : c_int = 21;
- pub const EINVAL : c_int = 22;
- pub const ENFILE : c_int = 23;
- pub const EMFILE : c_int = 24;
- pub const ENOTTY : c_int = 25;
- pub const ETXTBSY : c_int = 26;
- pub const EFBIG : c_int = 27;
- pub const ENOSPC : c_int = 28;
- pub const ESPIPE : c_int = 29;
- pub const EROFS : c_int = 30;
- pub const EMLINK : c_int = 31;
- pub const EPIPE : c_int = 32;
- pub const EDOM : c_int = 33;
- pub const ERANGE : c_int = 34;
+ pub const O_RDONLY: c_int = 0;
+ pub const O_WRONLY: c_int = 1;
+ pub const O_RDWR: c_int = 2;
+ pub const O_APPEND: c_int = 8;
+ pub const O_CREAT: c_int = 256;
+ pub const O_EXCL: c_int = 1024;
+ pub const O_NOCTTY: c_int = 2048;
+ pub const O_TRUNC: c_int = 512;
+ pub const S_IFIFO: mode_t = 4096;
+ pub const S_IFCHR: mode_t = 8192;
+ pub const S_IFBLK: mode_t = 24576;
+ pub const S_IFDIR: mode_t = 16384;
+ pub const S_IFREG: mode_t = 32768;
+ pub const S_IFLNK: mode_t = 40960;
+ pub const S_IFSOCK: mode_t = 49152;
+ pub const S_IFMT: mode_t = 61440;
+ pub const S_IEXEC: mode_t = 64;
+ pub const S_IWRITE: mode_t = 128;
+ pub const S_IREAD: mode_t = 256;
+ pub const S_IRWXU: mode_t = 448;
+ pub const S_IXUSR: mode_t = 64;
+ pub const S_IWUSR: mode_t = 128;
+ pub const S_IRUSR: mode_t = 256;
+ pub const S_IRWXG: mode_t = 56;
+ pub const S_IXGRP: mode_t = 8;
+ pub const S_IWGRP: mode_t = 16;
+ pub const S_IRGRP: mode_t = 32;
+ pub const S_IRWXO: mode_t = 7;
+ pub const S_IXOTH: mode_t = 1;
+ pub const S_IWOTH: mode_t = 2;
+ pub const S_IROTH: mode_t = 4;
+ pub const F_OK: c_int = 0;
+ pub const R_OK: c_int = 4;
+ pub const W_OK: c_int = 2;
+ pub const X_OK: c_int = 1;
+ pub const STDIN_FILENO: c_int = 0;
+ pub const STDOUT_FILENO: c_int = 1;
+ pub const STDERR_FILENO: c_int = 2;
+ pub const F_LOCK: c_int = 1;
+ pub const F_TEST: c_int = 3;
+ pub const F_TLOCK: c_int = 2;
+ pub const F_ULOCK: c_int = 0;
+ pub const SIGHUP: c_int = 1;
+ pub const SIGINT: c_int = 2;
+ pub const SIGQUIT: c_int = 3;
+ pub const SIGILL: c_int = 4;
+ pub const SIGABRT: c_int = 6;
+ pub const SIGFPE: c_int = 8;
+ pub const SIGKILL: c_int = 9;
+ pub const SIGSEGV: c_int = 11;
+ pub const SIGPIPE: c_int = 13;
+ pub const SIGALRM: c_int = 14;
+ pub const SIGTERM: c_int = 15;
+
+ pub const PROT_NONE: c_int = 0;
+ pub const PROT_READ: c_int = 1;
+ pub const PROT_WRITE: c_int = 2;
+ pub const PROT_EXEC: c_int = 4;
+
+ pub const MAP_FILE: c_int = 0x0000;
+ pub const MAP_SHARED: c_int = 0x0001;
+ pub const MAP_PRIVATE: c_int = 0x0002;
+ pub const MAP_FIXED: c_int = 0x0010;
+ pub const MAP_ANON: c_int = 0x0800;
+
+ pub const MAP_FAILED: *mut c_void = !0 as *mut c_void;
+
+ pub const MCL_CURRENT: c_int = 0x0001;
+ pub const MCL_FUTURE: c_int = 0x0002;
+
+ pub const MS_ASYNC: c_int = 0x0001;
+ pub const MS_INVALIDATE: c_int = 0x0002;
+ pub const MS_SYNC: c_int = 0x0004;
+
+ pub const EPERM: c_int = 1;
+ pub const ENOENT: c_int = 2;
+ pub const ESRCH: c_int = 3;
+ pub const EINTR: c_int = 4;
+ pub const EIO: c_int = 5;
+ pub const ENXIO: c_int = 6;
+ pub const E2BIG: c_int = 7;
+ pub const ENOEXEC: c_int = 8;
+ pub const EBADF: c_int = 9;
+ pub const ECHILD: c_int = 10;
+ pub const EAGAIN: c_int = 11;
+ pub const ENOMEM: c_int = 12;
+ pub const EACCES: c_int = 13;
+ pub const EFAULT: c_int = 14;
+ pub const ENOTBLK: c_int = 15;
+ pub const EBUSY: c_int = 16;
+ pub const EEXIST: c_int = 17;
+ pub const EXDEV: c_int = 18;
+ pub const ENODEV: c_int = 19;
+ pub const ENOTDIR: c_int = 20;
+ pub const EISDIR: c_int = 21;
+ pub const EINVAL: c_int = 22;
+ pub const ENFILE: c_int = 23;
+ pub const EMFILE: c_int = 24;
+ pub const ENOTTY: c_int = 25;
+ pub const ETXTBSY: c_int = 26;
+ pub const EFBIG: c_int = 27;
+ pub const ENOSPC: c_int = 28;
+ pub const ESPIPE: c_int = 29;
+ pub const EROFS: c_int = 30;
+ pub const EMLINK: c_int = 31;
+ pub const EPIPE: c_int = 32;
+ pub const EDOM: c_int = 33;
+ pub const ERANGE: c_int = 34;
pub const ENOMSG: c_int = 35;
pub const EIDRM: c_int = 36;
use types::os::arch::c95::{c_int, size_t};
use types::os::common::posix01::rlim_t;
- pub const F_DUPFD : c_int = 0;
- pub const F_GETFD : c_int = 1;
- pub const F_SETFD : c_int = 2;
- pub const F_GETFL : c_int = 3;
- pub const F_SETFL : c_int = 4;
+ pub const F_DUPFD: c_int = 0;
+ pub const F_GETFD: c_int = 1;
+ pub const F_SETFD: c_int = 2;
+ pub const F_GETFL: c_int = 3;
+ pub const F_SETFL: c_int = 4;
- pub const O_ACCMODE : c_int = 3;
+ pub const O_ACCMODE: c_int = 3;
- pub const SIGTRAP : c_int = 5;
+ pub const SIGTRAP: c_int = 5;
pub const SIG_IGN: size_t = 1;
- pub const GLOB_ERR : c_int = 1 << 0;
- pub const GLOB_MARK : c_int = 1 << 1;
- pub const GLOB_NOSORT : c_int = 1 << 2;
- pub const GLOB_DOOFFS : c_int = 1 << 3;
- pub const GLOB_NOCHECK : c_int = 1 << 4;
- pub const GLOB_APPEND : c_int = 1 << 5;
- pub const GLOB_NOESCAPE : c_int = 1 << 6;
-
- pub const GLOB_NOSPACE : c_int = 1;
- pub const GLOB_ABORTED : c_int = 2;
- pub const GLOB_NOMATCH : c_int = 3;
-
- pub const POSIX_MADV_NORMAL : c_int = 0;
- pub const POSIX_MADV_RANDOM : c_int = 1;
- pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
- pub const POSIX_MADV_WILLNEED : c_int = 3;
- pub const POSIX_MADV_DONTNEED : c_int = 4;
-
- pub const _SC_MQ_PRIO_MAX : c_int = 28;
- pub const _SC_IOV_MAX : c_int = 60;
- pub const _SC_GETGR_R_SIZE_MAX : c_int = 69;
- pub const _SC_GETPW_R_SIZE_MAX : c_int = 70;
- pub const _SC_LOGIN_NAME_MAX : c_int = 71;
- pub const _SC_TTY_NAME_MAX : c_int = 72;
- pub const _SC_THREADS : c_int = 67;
- pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 68;
- pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73;
- pub const _SC_THREAD_KEYS_MAX : c_int = 74;
- pub const _SC_THREAD_STACK_MIN : c_int = 75;
- pub const _SC_THREAD_THREADS_MAX : c_int = 76;
- pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77;
- pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78;
- pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79;
- pub const _SC_THREAD_PRIO_INHERIT : c_int = 80;
- pub const _SC_THREAD_PRIO_PROTECT : c_int = 81;
- pub const _SC_THREAD_PROCESS_SHARED : c_int = 82;
- pub const _SC_ATEXIT_MAX : c_int = 87;
- pub const _SC_XOPEN_VERSION : c_int = 89;
- pub const _SC_XOPEN_XCU_VERSION : c_int = 90;
- pub const _SC_XOPEN_UNIX : c_int = 91;
- pub const _SC_XOPEN_CRYPT : c_int = 92;
- pub const _SC_XOPEN_ENH_I18N : c_int = 93;
- pub const _SC_XOPEN_SHM : c_int = 94;
- pub const _SC_XOPEN_LEGACY : c_int = 129;
- pub const _SC_XOPEN_REALTIME : c_int = 130;
- pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131;
+ pub const GLOB_ERR: c_int = 1 << 0;
+ pub const GLOB_MARK: c_int = 1 << 1;
+ pub const GLOB_NOSORT: c_int = 1 << 2;
+ pub const GLOB_DOOFFS: c_int = 1 << 3;
+ pub const GLOB_NOCHECK: c_int = 1 << 4;
+ pub const GLOB_APPEND: c_int = 1 << 5;
+ pub const GLOB_NOESCAPE: c_int = 1 << 6;
+
+ pub const GLOB_NOSPACE: c_int = 1;
+ pub const GLOB_ABORTED: c_int = 2;
+ pub const GLOB_NOMATCH: c_int = 3;
+
+ pub const POSIX_MADV_NORMAL: c_int = 0;
+ pub const POSIX_MADV_RANDOM: c_int = 1;
+ pub const POSIX_MADV_SEQUENTIAL: c_int = 2;
+ pub const POSIX_MADV_WILLNEED: c_int = 3;
+ pub const POSIX_MADV_DONTNEED: c_int = 4;
+
+ pub const _SC_MQ_PRIO_MAX: c_int = 28;
+ pub const _SC_IOV_MAX: c_int = 60;
+ pub const _SC_GETGR_R_SIZE_MAX: c_int = 69;
+ pub const _SC_GETPW_R_SIZE_MAX: c_int = 70;
+ pub const _SC_LOGIN_NAME_MAX: c_int = 71;
+ pub const _SC_TTY_NAME_MAX: c_int = 72;
+ pub const _SC_THREADS: c_int = 67;
+ pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68;
+ pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73;
+ pub const _SC_THREAD_KEYS_MAX: c_int = 74;
+ pub const _SC_THREAD_STACK_MIN: c_int = 75;
+ pub const _SC_THREAD_THREADS_MAX: c_int = 76;
+ pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77;
+ pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78;
+ pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79;
+ pub const _SC_THREAD_PRIO_INHERIT: c_int = 80;
+ pub const _SC_THREAD_PRIO_PROTECT: c_int = 81;
+ pub const _SC_THREAD_PROCESS_SHARED: c_int = 82;
+ pub const _SC_ATEXIT_MAX: c_int = 87;
+ pub const _SC_XOPEN_VERSION: c_int = 89;
+ pub const _SC_XOPEN_XCU_VERSION: c_int = 90;
+ pub const _SC_XOPEN_UNIX: c_int = 91;
+ pub const _SC_XOPEN_CRYPT: c_int = 92;
+ pub const _SC_XOPEN_ENH_I18N: c_int = 93;
+ pub const _SC_XOPEN_SHM: c_int = 94;
+ pub const _SC_XOPEN_LEGACY: c_int = 129;
+ pub const _SC_XOPEN_REALTIME: c_int = 130;
+ pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131;
use types::os::arch::c95::{c_int, size_t};
use types::os::common::posix01::rlim_t;
- pub const F_DUPFD : c_int = 0;
- pub const F_GETFD : c_int = 1;
- pub const F_SETFD : c_int = 2;
- pub const F_GETFL : c_int = 3;
- pub const F_SETFL : c_int = 4;
+ pub const F_DUPFD: c_int = 0;
+ pub const F_GETFD: c_int = 1;
+ pub const F_SETFD: c_int = 2;
+ pub const F_GETFL: c_int = 3;
+ pub const F_SETFL: c_int = 4;
- pub const SIGTRAP : c_int = 5;
+ pub const SIGTRAP: c_int = 5;
pub const SIG_IGN: size_t = 1;
- pub const GLOB_ERR : c_int = 1 << 0;
- pub const GLOB_MARK : c_int = 1 << 1;
- pub const GLOB_NOSORT : c_int = 1 << 2;
- pub const GLOB_DOOFFS : c_int = 1 << 3;
- pub const GLOB_NOCHECK : c_int = 1 << 4;
- pub const GLOB_APPEND : c_int = 1 << 5;
- pub const GLOB_NOESCAPE : c_int = 1 << 6;
-
- pub const GLOB_NOSPACE : c_int = 1;
- pub const GLOB_ABORTED : c_int = 2;
- pub const GLOB_NOMATCH : c_int = 3;
-
- pub const POSIX_MADV_NORMAL : c_int = 0;
- pub const POSIX_MADV_RANDOM : c_int = 1;
- pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
- pub const POSIX_MADV_WILLNEED : c_int = 3;
- pub const POSIX_MADV_DONTNEED : c_int = 4;
-
- pub const _SC_MQ_PRIO_MAX : c_int = 28;
- pub const _SC_IOV_MAX : c_int = 60;
- pub const _SC_GETGR_R_SIZE_MAX : c_int = 69;
- pub const _SC_GETPW_R_SIZE_MAX : c_int = 70;
- pub const _SC_LOGIN_NAME_MAX : c_int = 71;
- pub const _SC_TTY_NAME_MAX : c_int = 72;
- pub const _SC_THREADS : c_int = 67;
- pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 68;
- pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 73;
- pub const _SC_THREAD_KEYS_MAX : c_int = 74;
- pub const _SC_THREAD_STACK_MIN : c_int = 75;
- pub const _SC_THREAD_THREADS_MAX : c_int = 76;
- pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77;
- pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78;
- pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 79;
- pub const _SC_THREAD_PRIO_INHERIT : c_int = 80;
- pub const _SC_THREAD_PRIO_PROTECT : c_int = 81;
- pub const _SC_THREAD_PROCESS_SHARED : c_int = 82;
- pub const _SC_ATEXIT_MAX : c_int = 87;
- pub const _SC_XOPEN_VERSION : c_int = 89;
- pub const _SC_XOPEN_XCU_VERSION : c_int = 90;
- pub const _SC_XOPEN_UNIX : c_int = 91;
- pub const _SC_XOPEN_CRYPT : c_int = 92;
- pub const _SC_XOPEN_ENH_I18N : c_int = 93;
- pub const _SC_XOPEN_SHM : c_int = 94;
- pub const _SC_XOPEN_LEGACY : c_int = 129;
- pub const _SC_XOPEN_REALTIME : c_int = 130;
- pub const _SC_XOPEN_REALTIME_THREADS : c_int = 131;
+ pub const GLOB_ERR: c_int = 1 << 0;
+ pub const GLOB_MARK: c_int = 1 << 1;
+ pub const GLOB_NOSORT: c_int = 1 << 2;
+ pub const GLOB_DOOFFS: c_int = 1 << 3;
+ pub const GLOB_NOCHECK: c_int = 1 << 4;
+ pub const GLOB_APPEND: c_int = 1 << 5;
+ pub const GLOB_NOESCAPE: c_int = 1 << 6;
+
+ pub const GLOB_NOSPACE: c_int = 1;
+ pub const GLOB_ABORTED: c_int = 2;
+ pub const GLOB_NOMATCH: c_int = 3;
+
+ pub const POSIX_MADV_NORMAL: c_int = 0;
+ pub const POSIX_MADV_RANDOM: c_int = 1;
+ pub const POSIX_MADV_SEQUENTIAL: c_int = 2;
+ pub const POSIX_MADV_WILLNEED: c_int = 3;
+ pub const POSIX_MADV_DONTNEED: c_int = 4;
+
+ pub const _SC_MQ_PRIO_MAX: c_int = 28;
+ pub const _SC_IOV_MAX: c_int = 60;
+ pub const _SC_GETGR_R_SIZE_MAX: c_int = 69;
+ pub const _SC_GETPW_R_SIZE_MAX: c_int = 70;
+ pub const _SC_LOGIN_NAME_MAX: c_int = 71;
+ pub const _SC_TTY_NAME_MAX: c_int = 72;
+ pub const _SC_THREADS: c_int = 67;
+ pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 68;
+ pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 73;
+ pub const _SC_THREAD_KEYS_MAX: c_int = 74;
+ pub const _SC_THREAD_STACK_MIN: c_int = 75;
+ pub const _SC_THREAD_THREADS_MAX: c_int = 76;
+ pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77;
+ pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78;
+ pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 79;
+ pub const _SC_THREAD_PRIO_INHERIT: c_int = 80;
+ pub const _SC_THREAD_PRIO_PROTECT: c_int = 81;
+ pub const _SC_THREAD_PROCESS_SHARED: c_int = 82;
+ pub const _SC_ATEXIT_MAX: c_int = 87;
+ pub const _SC_XOPEN_VERSION: c_int = 89;
+ pub const _SC_XOPEN_XCU_VERSION: c_int = 90;
+ pub const _SC_XOPEN_UNIX: c_int = 91;
+ pub const _SC_XOPEN_CRYPT: c_int = 92;
+ pub const _SC_XOPEN_ENH_I18N: c_int = 93;
+ pub const _SC_XOPEN_SHM: c_int = 94;
+ pub const _SC_XOPEN_LEGACY: c_int = 129;
+ pub const _SC_XOPEN_REALTIME: c_int = 130;
+ pub const _SC_XOPEN_REALTIME_THREADS: c_int = 131;
pub const PTHREAD_CREATE_JOINABLE: c_int = 1;
pub const PTHREAD_CREATE_DETACHED: c_int = 0;
pub mod bsd44 {
use types::os::arch::c95::c_int;
- pub const MADV_NORMAL : c_int = 0;
- pub const MADV_RANDOM : c_int = 1;
- pub const MADV_SEQUENTIAL : c_int = 2;
- pub const MADV_WILLNEED : c_int = 3;
- pub const MADV_DONTNEED : c_int = 4;
- pub const MADV_REMOVE : c_int = 9;
- pub const MADV_DONTFORK : c_int = 10;
- pub const MADV_DOFORK : c_int = 11;
- pub const MADV_MERGEABLE : c_int = 12;
- pub const MADV_UNMERGEABLE : c_int = 13;
- pub const MADV_HWPOISON : c_int = 100;
+ pub const MADV_NORMAL: c_int = 0;
+ pub const MADV_RANDOM: c_int = 1;
+ pub const MADV_SEQUENTIAL: c_int = 2;
+ pub const MADV_WILLNEED: c_int = 3;
+ pub const MADV_DONTNEED: c_int = 4;
+ pub const MADV_REMOVE: c_int = 9;
+ pub const MADV_DONTFORK: c_int = 10;
+ pub const MADV_DOFORK: c_int = 11;
+ pub const MADV_MERGEABLE: c_int = 12;
+ pub const MADV_UNMERGEABLE: c_int = 13;
+ pub const MADV_HWPOISON: c_int = 100;
pub const IFF_LOOPBACK: c_int = 0x8;
pub mod bsd44 {
use types::os::arch::c95::c_int;
- pub const MADV_NORMAL : c_int = 0;
- pub const MADV_RANDOM : c_int = 1;
- pub const MADV_SEQUENTIAL : c_int = 2;
- pub const MADV_WILLNEED : c_int = 3;
- pub const MADV_DONTNEED : c_int = 4;
- pub const MADV_REMOVE : c_int = 9;
- pub const MADV_DONTFORK : c_int = 10;
- pub const MADV_DOFORK : c_int = 11;
- pub const MADV_MERGEABLE : c_int = 12;
- pub const MADV_UNMERGEABLE : c_int = 13;
- pub const MADV_HWPOISON : c_int = 100;
+ pub const MADV_NORMAL: c_int = 0;
+ pub const MADV_RANDOM: c_int = 1;
+ pub const MADV_SEQUENTIAL: c_int = 2;
+ pub const MADV_WILLNEED: c_int = 3;
+ pub const MADV_DONTNEED: c_int = 4;
+ pub const MADV_REMOVE: c_int = 9;
+ pub const MADV_DONTFORK: c_int = 10;
+ pub const MADV_DOFORK: c_int = 11;
+ pub const MADV_MERGEABLE: c_int = 12;
+ pub const MADV_UNMERGEABLE: c_int = 13;
+ pub const MADV_HWPOISON: c_int = 100;
pub const AF_UNIX: c_int = 1;
pub const AF_INET: c_int = 2;
pub mod extra {
use types::os::arch::c95::c_int;
- pub const AF_PACKET : c_int = 17;
- pub const IPPROTO_RAW : c_int = 255;
-
- pub const O_RSYNC : c_int = 1052672;
- pub const O_DSYNC : c_int = 4096;
- pub const O_NONBLOCK : c_int = 2048;
- pub const O_SYNC : c_int = 1052672;
-
- pub const PROT_GROWSDOWN : c_int = 0x010000000;
- pub const PROT_GROWSUP : c_int = 0x020000000;
-
- pub const MAP_TYPE : c_int = 0x000f;
- pub const MAP_ANONYMOUS : c_int = 0x0020;
- pub const MAP_32BIT : c_int = 0x0040;
- pub const MAP_GROWSDOWN : c_int = 0x0100;
- pub const MAP_DENYWRITE : c_int = 0x0800;
- pub const MAP_EXECUTABLE : c_int = 0x01000;
- pub const MAP_LOCKED : c_int = 0x02000;
- pub const MAP_NORESERVE : c_int = 0x04000;
- pub const MAP_POPULATE : c_int = 0x08000;
- pub const MAP_NONBLOCK : c_int = 0x010000;
- pub const MAP_STACK : c_int = 0x020000;
+ pub const AF_PACKET: c_int = 17;
+ pub const IPPROTO_RAW: c_int = 255;
+
+ pub const O_RSYNC: c_int = 1052672;
+ pub const O_DSYNC: c_int = 4096;
+ pub const O_NONBLOCK: c_int = 2048;
+ pub const O_SYNC: c_int = 1052672;
+
+ pub const PROT_GROWSDOWN: c_int = 0x010000000;
+ pub const PROT_GROWSUP: c_int = 0x020000000;
+
+ pub const MAP_TYPE: c_int = 0x000f;
+ pub const MAP_ANONYMOUS: c_int = 0x0020;
+ pub const MAP_32BIT: c_int = 0x0040;
+ pub const MAP_GROWSDOWN: c_int = 0x0100;
+ pub const MAP_DENYWRITE: c_int = 0x0800;
+ pub const MAP_EXECUTABLE: c_int = 0x01000;
+ pub const MAP_LOCKED: c_int = 0x02000;
+ pub const MAP_NORESERVE: c_int = 0x04000;
+ pub const MAP_POPULATE: c_int = 0x08000;
+ pub const MAP_NONBLOCK: c_int = 0x010000;
+ pub const MAP_STACK: c_int = 0x020000;
+
+ pub const PATH_MAX: c_int = 4096;
}
#[cfg(any(target_arch = "mips",
target_arch = "mipsel"))]
pub mod extra {
use types::os::arch::c95::c_int;
- pub const AF_PACKET : c_int = 17;
- pub const IPPROTO_RAW : c_int = 255;
-
- pub const O_RSYNC : c_int = 16400;
- pub const O_DSYNC : c_int = 16;
- pub const O_NONBLOCK : c_int = 128;
- pub const O_SYNC : c_int = 16400;
-
- pub const PROT_GROWSDOWN : c_int = 0x01000000;
- pub const PROT_GROWSUP : c_int = 0x02000000;
-
- pub const MAP_TYPE : c_int = 0x000f;
- pub const MAP_ANONYMOUS : c_int = 0x0800;
- pub const MAP_GROWSDOWN : c_int = 0x01000;
- pub const MAP_DENYWRITE : c_int = 0x02000;
- pub const MAP_EXECUTABLE : c_int = 0x04000;
- pub const MAP_LOCKED : c_int = 0x08000;
- pub const MAP_NORESERVE : c_int = 0x0400;
- pub const MAP_POPULATE : c_int = 0x010000;
- pub const MAP_NONBLOCK : c_int = 0x020000;
- pub const MAP_STACK : c_int = 0x040000;
+ pub const AF_PACKET: c_int = 17;
+ pub const IPPROTO_RAW: c_int = 255;
+
+ pub const O_RSYNC: c_int = 16400;
+ pub const O_DSYNC: c_int = 16;
+ pub const O_NONBLOCK: c_int = 128;
+ pub const O_SYNC: c_int = 16400;
+
+ pub const PROT_GROWSDOWN: c_int = 0x01000000;
+ pub const PROT_GROWSUP: c_int = 0x02000000;
+
+ pub const MAP_TYPE: c_int = 0x000f;
+ pub const MAP_ANONYMOUS: c_int = 0x0800;
+ pub const MAP_GROWSDOWN: c_int = 0x01000;
+ pub const MAP_DENYWRITE: c_int = 0x02000;
+ pub const MAP_EXECUTABLE: c_int = 0x04000;
+ pub const MAP_LOCKED: c_int = 0x08000;
+ pub const MAP_NORESERVE: c_int = 0x0400;
+ pub const MAP_POPULATE: c_int = 0x010000;
+ pub const MAP_NONBLOCK: c_int = 0x020000;
+ pub const MAP_STACK: c_int = 0x040000;
+
+ pub const PATH_MAX: c_int = 4096;
}
#[cfg(target_os = "linux")]
pub mod sysconf {
use types::os::arch::c95::c_int;
- pub const _SC_ARG_MAX : c_int = 0;
- pub const _SC_CHILD_MAX : c_int = 1;
- pub const _SC_CLK_TCK : c_int = 2;
- pub const _SC_NGROUPS_MAX : c_int = 3;
- pub const _SC_OPEN_MAX : c_int = 4;
- pub const _SC_STREAM_MAX : c_int = 5;
- pub const _SC_TZNAME_MAX : c_int = 6;
- pub const _SC_JOB_CONTROL : c_int = 7;
- pub const _SC_SAVED_IDS : c_int = 8;
- pub const _SC_REALTIME_SIGNALS : c_int = 9;
- pub const _SC_PRIORITY_SCHEDULING : c_int = 10;
- pub const _SC_TIMERS : c_int = 11;
- pub const _SC_ASYNCHRONOUS_IO : c_int = 12;
- pub const _SC_PRIORITIZED_IO : c_int = 13;
- pub const _SC_SYNCHRONIZED_IO : c_int = 14;
- pub const _SC_FSYNC : c_int = 15;
- pub const _SC_MAPPED_FILES : c_int = 16;
- pub const _SC_MEMLOCK : c_int = 17;
- pub const _SC_MEMLOCK_RANGE : c_int = 18;
- pub const _SC_MEMORY_PROTECTION : c_int = 19;
- pub const _SC_MESSAGE_PASSING : c_int = 20;
- pub const _SC_SEMAPHORES : c_int = 21;
- pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 22;
- pub const _SC_AIO_LISTIO_MAX : c_int = 23;
- pub const _SC_AIO_MAX : c_int = 24;
- pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 25;
- pub const _SC_DELAYTIMER_MAX : c_int = 26;
- pub const _SC_MQ_OPEN_MAX : c_int = 27;
- pub const _SC_VERSION : c_int = 29;
- pub const _SC_PAGESIZE : c_int = 30;
- pub const _SC_RTSIG_MAX : c_int = 31;
- pub const _SC_SEM_NSEMS_MAX : c_int = 32;
- pub const _SC_SEM_VALUE_MAX : c_int = 33;
- pub const _SC_SIGQUEUE_MAX : c_int = 34;
- pub const _SC_TIMER_MAX : c_int = 35;
- pub const _SC_BC_BASE_MAX : c_int = 36;
- pub const _SC_BC_DIM_MAX : c_int = 37;
- pub const _SC_BC_SCALE_MAX : c_int = 38;
- pub const _SC_BC_STRING_MAX : c_int = 39;
- pub const _SC_COLL_WEIGHTS_MAX : c_int = 40;
- pub const _SC_EXPR_NEST_MAX : c_int = 42;
- pub const _SC_LINE_MAX : c_int = 43;
- pub const _SC_RE_DUP_MAX : c_int = 44;
- pub const _SC_2_VERSION : c_int = 46;
- pub const _SC_2_C_BIND : c_int = 47;
- pub const _SC_2_C_DEV : c_int = 48;
- pub const _SC_2_FORT_DEV : c_int = 49;
- pub const _SC_2_FORT_RUN : c_int = 50;
- pub const _SC_2_SW_DEV : c_int = 51;
- pub const _SC_2_LOCALEDEF : c_int = 52;
- pub const _SC_NPROCESSORS_ONLN : c_int = 84;
- pub const _SC_2_CHAR_TERM : c_int = 95;
- pub const _SC_2_C_VERSION : c_int = 96;
- pub const _SC_2_UPE : c_int = 97;
- pub const _SC_XBS5_ILP32_OFF32 : c_int = 125;
- pub const _SC_XBS5_ILP32_OFFBIG : c_int = 126;
- pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 128;
+ pub const _SC_ARG_MAX: c_int = 0;
+ pub const _SC_CHILD_MAX: c_int = 1;
+ pub const _SC_CLK_TCK: c_int = 2;
+ pub const _SC_NGROUPS_MAX: c_int = 3;
+ pub const _SC_OPEN_MAX: c_int = 4;
+ pub const _SC_STREAM_MAX: c_int = 5;
+ pub const _SC_TZNAME_MAX: c_int = 6;
+ pub const _SC_JOB_CONTROL: c_int = 7;
+ pub const _SC_SAVED_IDS: c_int = 8;
+ pub const _SC_REALTIME_SIGNALS: c_int = 9;
+ pub const _SC_PRIORITY_SCHEDULING: c_int = 10;
+ pub const _SC_TIMERS: c_int = 11;
+ pub const _SC_ASYNCHRONOUS_IO: c_int = 12;
+ pub const _SC_PRIORITIZED_IO: c_int = 13;
+ pub const _SC_SYNCHRONIZED_IO: c_int = 14;
+ pub const _SC_FSYNC: c_int = 15;
+ pub const _SC_MAPPED_FILES: c_int = 16;
+ pub const _SC_MEMLOCK: c_int = 17;
+ pub const _SC_MEMLOCK_RANGE: c_int = 18;
+ pub const _SC_MEMORY_PROTECTION: c_int = 19;
+ pub const _SC_MESSAGE_PASSING: c_int = 20;
+ pub const _SC_SEMAPHORES: c_int = 21;
+ pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 22;
+ pub const _SC_AIO_LISTIO_MAX: c_int = 23;
+ pub const _SC_AIO_MAX: c_int = 24;
+ pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 25;
+ pub const _SC_DELAYTIMER_MAX: c_int = 26;
+ pub const _SC_MQ_OPEN_MAX: c_int = 27;
+ pub const _SC_VERSION: c_int = 29;
+ pub const _SC_PAGESIZE: c_int = 30;
+ pub const _SC_RTSIG_MAX: c_int = 31;
+ pub const _SC_SEM_NSEMS_MAX: c_int = 32;
+ pub const _SC_SEM_VALUE_MAX: c_int = 33;
+ pub const _SC_SIGQUEUE_MAX: c_int = 34;
+ pub const _SC_TIMER_MAX: c_int = 35;
+ pub const _SC_BC_BASE_MAX: c_int = 36;
+ pub const _SC_BC_DIM_MAX: c_int = 37;
+ pub const _SC_BC_SCALE_MAX: c_int = 38;
+ pub const _SC_BC_STRING_MAX: c_int = 39;
+ pub const _SC_COLL_WEIGHTS_MAX: c_int = 40;
+ pub const _SC_EXPR_NEST_MAX: c_int = 42;
+ pub const _SC_LINE_MAX: c_int = 43;
+ pub const _SC_RE_DUP_MAX: c_int = 44;
+ pub const _SC_2_VERSION: c_int = 46;
+ pub const _SC_2_C_BIND: c_int = 47;
+ pub const _SC_2_C_DEV: c_int = 48;
+ pub const _SC_2_FORT_DEV: c_int = 49;
+ pub const _SC_2_FORT_RUN: c_int = 50;
+ pub const _SC_2_SW_DEV: c_int = 51;
+ pub const _SC_2_LOCALEDEF: c_int = 52;
+ pub const _SC_NPROCESSORS_ONLN: c_int = 84;
+ pub const _SC_2_CHAR_TERM: c_int = 95;
+ pub const _SC_2_C_VERSION: c_int = 96;
+ pub const _SC_2_UPE: c_int = 97;
+ pub const _SC_XBS5_ILP32_OFF32: c_int = 125;
+ pub const _SC_XBS5_ILP32_OFFBIG: c_int = 126;
+ pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 128;
pub const _PC_NAME_MAX: c_int = 3;
pub const _PC_PATH_MAX: c_int = 4;
pub mod sysconf {
use types::os::arch::c95::c_int;
- pub static _SC_SENDMSG_MAX_SIZE : c_int = 0;
- pub static _SC_NPROCESSORS_ONLN : c_int = 1;
- pub static _SC_PAGESIZE : c_int = 2;
+ pub static _SC_SENDMSG_MAX_SIZE: c_int = 0;
+ pub static _SC_NPROCESSORS_ONLN: c_int = 1;
+ pub static _SC_PAGESIZE: c_int = 2;
pub const _PC_NAME_MAX: c_int = 3;
pub const _PC_PATH_MAX: c_int = 4;
pub mod sysconf {
use types::os::arch::c95::c_int;
- pub const _SC_ARG_MAX : c_int = 0;
- pub const _SC_BC_BASE_MAX : c_int = 1;
- pub const _SC_BC_DIM_MAX : c_int = 2;
- pub const _SC_BC_SCALE_MAX : c_int = 3;
- pub const _SC_BC_STRING_MAX : c_int = 4;
- pub const _SC_CHILD_MAX : c_int = 5;
- pub const _SC_CLK_TCK : c_int = 6;
- pub const _SC_COLL_WEIGHTS_MAX : c_int = 7;
- pub const _SC_EXPR_NEST_MAX : c_int = 8;
- pub const _SC_LINE_MAX : c_int = 9;
- pub const _SC_NGROUPS_MAX : c_int = 10;
- pub const _SC_OPEN_MAX : c_int = 11;
- pub const _SC_2_C_BIND : c_int = 13;
- pub const _SC_2_C_DEV : c_int = 14;
- pub const _SC_2_C_VERSION : c_int = 15;
- pub const _SC_2_CHAR_TERM : c_int = 16;
- pub const _SC_2_FORT_DEV : c_int = 17;
- pub const _SC_2_FORT_RUN : c_int = 18;
- pub const _SC_2_LOCALEDEF : c_int = 19;
- pub const _SC_2_SW_DEV : c_int = 20;
- pub const _SC_2_UPE : c_int = 21;
- pub const _SC_2_VERSION : c_int = 22;
- pub const _SC_JOB_CONTROL : c_int = 23;
- pub const _SC_SAVED_IDS : c_int = 24;
- pub const _SC_VERSION : c_int = 25;
- pub const _SC_RE_DUP_MAX : c_int = 26;
- pub const _SC_STREAM_MAX : c_int = 27;
- pub const _SC_TZNAME_MAX : c_int = 28;
- pub const _SC_PAGESIZE : c_int = 39;
+ pub const _SC_ARG_MAX: c_int = 0;
+ pub const _SC_BC_BASE_MAX: c_int = 1;
+ pub const _SC_BC_DIM_MAX: c_int = 2;
+ pub const _SC_BC_SCALE_MAX: c_int = 3;
+ pub const _SC_BC_STRING_MAX: c_int = 4;
+ pub const _SC_CHILD_MAX: c_int = 5;
+ pub const _SC_CLK_TCK: c_int = 6;
+ pub const _SC_COLL_WEIGHTS_MAX: c_int = 7;
+ pub const _SC_EXPR_NEST_MAX: c_int = 8;
+ pub const _SC_LINE_MAX: c_int = 9;
+ pub const _SC_NGROUPS_MAX: c_int = 10;
+ pub const _SC_OPEN_MAX: c_int = 11;
+ pub const _SC_2_C_BIND: c_int = 13;
+ pub const _SC_2_C_DEV: c_int = 14;
+ pub const _SC_2_C_VERSION: c_int = 15;
+ pub const _SC_2_CHAR_TERM: c_int = 16;
+ pub const _SC_2_FORT_DEV: c_int = 17;
+ pub const _SC_2_FORT_RUN: c_int = 18;
+ pub const _SC_2_LOCALEDEF: c_int = 19;
+ pub const _SC_2_SW_DEV: c_int = 20;
+ pub const _SC_2_UPE: c_int = 21;
+ pub const _SC_2_VERSION: c_int = 22;
+ pub const _SC_JOB_CONTROL: c_int = 23;
+ pub const _SC_SAVED_IDS: c_int = 24;
+ pub const _SC_VERSION: c_int = 25;
+ pub const _SC_RE_DUP_MAX: c_int = 26;
+ pub const _SC_STREAM_MAX: c_int = 27;
+ pub const _SC_TZNAME_MAX: c_int = 28;
+ pub const _SC_PAGESIZE: c_int = 39;
pub const _PC_NAME_MAX: c_int = 4;
pub const _PC_PATH_MAX: c_int = 5;
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
- pub const EXIT_FAILURE : c_int = 1;
- pub const EXIT_SUCCESS : c_int = 0;
- pub const RAND_MAX : c_int = 2147483647;
- pub const EOF : c_int = -1;
- pub const SEEK_SET : c_int = 0;
- pub const SEEK_CUR : c_int = 1;
- pub const SEEK_END : c_int = 2;
- pub const _IOFBF : c_int = 0;
- pub const _IONBF : c_int = 2;
- pub const _IOLBF : c_int = 1;
- pub const BUFSIZ : c_uint = 1024;
- pub const FOPEN_MAX : c_uint = 20;
- pub const FILENAME_MAX : c_uint = 1024;
- pub const L_tmpnam : c_uint = 1024;
- pub const TMP_MAX : c_uint = 308915776;
+ pub const EXIT_FAILURE: c_int = 1;
+ pub const EXIT_SUCCESS: c_int = 0;
+ pub const RAND_MAX: c_int = 2147483647;
+ pub const EOF: c_int = -1;
+ pub const SEEK_SET: c_int = 0;
+ pub const SEEK_CUR: c_int = 1;
+ pub const SEEK_END: c_int = 2;
+ pub const _IOFBF: c_int = 0;
+ pub const _IONBF: c_int = 2;
+ pub const _IOLBF: c_int = 1;
+ pub const BUFSIZ: c_uint = 1024;
+ pub const FOPEN_MAX: c_uint = 20;
+ pub const FILENAME_MAX: c_uint = 1024;
+ pub const L_tmpnam: c_uint = 1024;
+ pub const TMP_MAX: c_uint = 308915776;
}
pub mod c99 {
}
use types::os::arch::c95::c_int;
use types::os::arch::posix88::mode_t;
- pub const O_RDONLY : c_int = 0;
- pub const O_WRONLY : c_int = 1;
- pub const O_RDWR : c_int = 2;
- pub const O_APPEND : c_int = 8;
- pub const O_CREAT : c_int = 512;
- pub const O_EXCL : c_int = 2048;
- pub const O_NOCTTY : c_int = 32768;
- pub const O_TRUNC : c_int = 1024;
- pub const S_IFIFO : mode_t = 4096;
- pub const S_IFCHR : mode_t = 8192;
- pub const S_IFBLK : mode_t = 24576;
- pub const S_IFDIR : mode_t = 16384;
- pub const S_IFREG : mode_t = 32768;
- pub const S_IFLNK : mode_t = 40960;
- pub const S_IFSOCK : mode_t = 49152;
- pub const S_IFMT : mode_t = 61440;
- pub const S_IEXEC : mode_t = 64;
- pub const S_IWRITE : mode_t = 128;
- pub const S_IREAD : mode_t = 256;
- pub const S_IRWXU : mode_t = 448;
- pub const S_IXUSR : mode_t = 64;
- pub const S_IWUSR : mode_t = 128;
- pub const S_IRUSR : mode_t = 256;
- pub const S_IRWXG : mode_t = 56;
- pub const S_IXGRP : mode_t = 8;
- pub const S_IWGRP : mode_t = 16;
- pub const S_IRGRP : mode_t = 32;
- pub const S_IRWXO : mode_t = 7;
- pub const S_IXOTH : mode_t = 1;
- pub const S_IWOTH : mode_t = 2;
- pub const S_IROTH : mode_t = 4;
- pub const F_OK : c_int = 0;
- pub const R_OK : c_int = 4;
- pub const W_OK : c_int = 2;
- pub const X_OK : c_int = 1;
- pub const STDIN_FILENO : c_int = 0;
- pub const STDOUT_FILENO : c_int = 1;
- pub const STDERR_FILENO : c_int = 2;
- pub const F_LOCK : c_int = 1;
- pub const F_TEST : c_int = 3;
- pub const F_TLOCK : c_int = 2;
- pub const F_ULOCK : c_int = 0;
- pub const SIGHUP : c_int = 1;
- pub const SIGINT : c_int = 2;
- pub const SIGQUIT : c_int = 3;
- pub const SIGILL : c_int = 4;
- pub const SIGABRT : c_int = 6;
- pub const SIGFPE : c_int = 8;
- pub const SIGKILL : c_int = 9;
- pub const SIGSEGV : c_int = 11;
- pub const SIGPIPE : c_int = 13;
- pub const SIGALRM : c_int = 14;
- pub const SIGTERM : c_int = 15;
-
- pub const PROT_NONE : c_int = 0;
- pub const PROT_READ : c_int = 1;
- pub const PROT_WRITE : c_int = 2;
- pub const PROT_EXEC : c_int = 4;
-
- pub const MAP_FILE : c_int = 0x0000;
- pub const MAP_SHARED : c_int = 0x0001;
- pub const MAP_PRIVATE : c_int = 0x0002;
- pub const MAP_FIXED : c_int = 0x0010;
- pub const MAP_ANON : c_int = 0x1000;
-
- pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
-
- pub const MCL_CURRENT : c_int = 0x0001;
- pub const MCL_FUTURE : c_int = 0x0002;
-
- pub const MS_SYNC : c_int = 0x0000;
- pub const MS_ASYNC : c_int = 0x0001;
- pub const MS_INVALIDATE : c_int = 0x0002;
-
- pub const EPERM : c_int = 1;
- pub const ENOENT : c_int = 2;
- pub const ESRCH : c_int = 3;
- pub const EINTR : c_int = 4;
- pub const EIO : c_int = 5;
- pub const ENXIO : c_int = 6;
- pub const E2BIG : c_int = 7;
- pub const ENOEXEC : c_int = 8;
- pub const EBADF : c_int = 9;
- pub const ECHILD : c_int = 10;
- pub const EDEADLK : c_int = 11;
- pub const ENOMEM : c_int = 12;
- pub const EACCES : c_int = 13;
- pub const EFAULT : c_int = 14;
- pub const ENOTBLK : c_int = 15;
- pub const EBUSY : c_int = 16;
- pub const EEXIST : c_int = 17;
- pub const EXDEV : c_int = 18;
- pub const ENODEV : c_int = 19;
- pub const ENOTDIR : c_int = 20;
- pub const EISDIR : c_int = 21;
- pub const EINVAL : c_int = 22;
- pub const ENFILE : c_int = 23;
- pub const EMFILE : c_int = 24;
- pub const ENOTTY : c_int = 25;
- pub const ETXTBSY : c_int = 26;
- pub const EFBIG : c_int = 27;
- pub const ENOSPC : c_int = 28;
- pub const ESPIPE : c_int = 29;
- pub const EROFS : c_int = 30;
- pub const EMLINK : c_int = 31;
- pub const EPIPE : c_int = 32;
- pub const EDOM : c_int = 33;
- pub const ERANGE : c_int = 34;
- pub const EAGAIN : c_int = 35;
- pub const EWOULDBLOCK : c_int = 35;
- pub const EINPROGRESS : c_int = 36;
- pub const EALREADY : c_int = 37;
- pub const ENOTSOCK : c_int = 38;
- pub const EDESTADDRREQ : c_int = 39;
- pub const EMSGSIZE : c_int = 40;
- pub const EPROTOTYPE : c_int = 41;
- pub const ENOPROTOOPT : c_int = 42;
- pub const EPROTONOSUPPORT : c_int = 43;
- pub const ESOCKTNOSUPPORT : c_int = 44;
- pub const EOPNOTSUPP : c_int = 45;
- pub const EPFNOSUPPORT : c_int = 46;
- pub const EAFNOSUPPORT : c_int = 47;
- pub const EADDRINUSE : c_int = 48;
- pub const EADDRNOTAVAIL : c_int = 49;
- pub const ENETDOWN : c_int = 50;
- pub const ENETUNREACH : c_int = 51;
- pub const ENETRESET : c_int = 52;
- pub const ECONNABORTED : c_int = 53;
- pub const ECONNRESET : c_int = 54;
- pub const ENOBUFS : c_int = 55;
- pub const EISCONN : c_int = 56;
- pub const ENOTCONN : c_int = 57;
- pub const ESHUTDOWN : c_int = 58;
- pub const ETOOMANYREFS : c_int = 59;
- pub const ETIMEDOUT : c_int = 60;
- pub const ECONNREFUSED : c_int = 61;
- pub const ELOOP : c_int = 62;
- pub const ENAMETOOLONG : c_int = 63;
- pub const EHOSTDOWN : c_int = 64;
- pub const EHOSTUNREACH : c_int = 65;
- pub const ENOTEMPTY : c_int = 66;
- pub const EPROCLIM : c_int = 67;
- pub const EUSERS : c_int = 68;
- pub const EDQUOT : c_int = 69;
- pub const ESTALE : c_int = 70;
- pub const EREMOTE : c_int = 71;
- pub const EBADRPC : c_int = 72;
- pub const ERPCMISMATCH : c_int = 73;
- pub const EPROGUNAVAIL : c_int = 74;
- pub const EPROGMISMATCH : c_int = 75;
- pub const EPROCUNAVAIL : c_int = 76;
- pub const ENOLCK : c_int = 77;
- pub const ENOSYS : c_int = 78;
- pub const EFTYPE : c_int = 79;
- pub const EAUTH : c_int = 80;
- pub const ENEEDAUTH : c_int = 81;
- pub const EIDRM : c_int = 82;
- pub const ENOMSG : c_int = 83;
- pub const EOVERFLOW : c_int = 84;
- pub const ECANCELED : c_int = 85;
- pub const EILSEQ : c_int = 86;
- pub const ENOATTR : c_int = 87;
- pub const EDOOFUS : c_int = 88;
- pub const EBADMSG : c_int = 89;
- pub const EMULTIHOP : c_int = 90;
- pub const ENOLINK : c_int = 91;
- pub const EPROTO : c_int = 92;
- pub const ENOMEDIUM : c_int = 93;
- pub const EUNUSED94 : c_int = 94;
- pub const EUNUSED95 : c_int = 95;
- pub const EUNUSED96 : c_int = 96;
- pub const EUNUSED97 : c_int = 97;
- pub const EUNUSED98 : c_int = 98;
- pub const EASYNC : c_int = 99;
- pub const ELAST : c_int = 99;
+ pub const O_RDONLY: c_int = 0;
+ pub const O_WRONLY: c_int = 1;
+ pub const O_RDWR: c_int = 2;
+ pub const O_APPEND: c_int = 8;
+ pub const O_CREAT: c_int = 512;
+ pub const O_EXCL: c_int = 2048;
+ pub const O_NOCTTY: c_int = 32768;
+ pub const O_TRUNC: c_int = 1024;
+ pub const S_IFIFO: mode_t = 4096;
+ pub const S_IFCHR: mode_t = 8192;
+ pub const S_IFBLK: mode_t = 24576;
+ pub const S_IFDIR: mode_t = 16384;
+ pub const S_IFREG: mode_t = 32768;
+ pub const S_IFLNK: mode_t = 40960;
+ pub const S_IFSOCK: mode_t = 49152;
+ pub const S_IFMT: mode_t = 61440;
+ pub const S_IEXEC: mode_t = 64;
+ pub const S_IWRITE: mode_t = 128;
+ pub const S_IREAD: mode_t = 256;
+ pub const S_IRWXU: mode_t = 448;
+ pub const S_IXUSR: mode_t = 64;
+ pub const S_IWUSR: mode_t = 128;
+ pub const S_IRUSR: mode_t = 256;
+ pub const S_IRWXG: mode_t = 56;
+ pub const S_IXGRP: mode_t = 8;
+ pub const S_IWGRP: mode_t = 16;
+ pub const S_IRGRP: mode_t = 32;
+ pub const S_IRWXO: mode_t = 7;
+ pub const S_IXOTH: mode_t = 1;
+ pub const S_IWOTH: mode_t = 2;
+ pub const S_IROTH: mode_t = 4;
+ pub const F_OK: c_int = 0;
+ pub const R_OK: c_int = 4;
+ pub const W_OK: c_int = 2;
+ pub const X_OK: c_int = 1;
+ pub const STDIN_FILENO: c_int = 0;
+ pub const STDOUT_FILENO: c_int = 1;
+ pub const STDERR_FILENO: c_int = 2;
+ pub const F_LOCK: c_int = 1;
+ pub const F_TEST: c_int = 3;
+ pub const F_TLOCK: c_int = 2;
+ pub const F_ULOCK: c_int = 0;
+ pub const SIGHUP: c_int = 1;
+ pub const SIGINT: c_int = 2;
+ pub const SIGQUIT: c_int = 3;
+ pub const SIGILL: c_int = 4;
+ pub const SIGABRT: c_int = 6;
+ pub const SIGFPE: c_int = 8;
+ pub const SIGKILL: c_int = 9;
+ pub const SIGSEGV: c_int = 11;
+ pub const SIGPIPE: c_int = 13;
+ pub const SIGALRM: c_int = 14;
+ pub const SIGTERM: c_int = 15;
+
+ pub const PROT_NONE: c_int = 0;
+ pub const PROT_READ: c_int = 1;
+ pub const PROT_WRITE: c_int = 2;
+ pub const PROT_EXEC: c_int = 4;
+
+ pub const MAP_FILE: c_int = 0x0000;
+ pub const MAP_SHARED: c_int = 0x0001;
+ pub const MAP_PRIVATE: c_int = 0x0002;
+ pub const MAP_FIXED: c_int = 0x0010;
+ pub const MAP_ANON: c_int = 0x1000;
+
+ pub const MAP_FAILED: *mut c_void = !0 as *mut c_void;
+
+ pub const MCL_CURRENT: c_int = 0x0001;
+ pub const MCL_FUTURE: c_int = 0x0002;
+
+ pub const MS_SYNC: c_int = 0x0000;
+ pub const MS_ASYNC: c_int = 0x0001;
+ pub const MS_INVALIDATE: c_int = 0x0002;
+
+ pub const EPERM: c_int = 1;
+ pub const ENOENT: c_int = 2;
+ pub const ESRCH: c_int = 3;
+ pub const EINTR: c_int = 4;
+ pub const EIO: c_int = 5;
+ pub const ENXIO: c_int = 6;
+ pub const E2BIG: c_int = 7;
+ pub const ENOEXEC: c_int = 8;
+ pub const EBADF: c_int = 9;
+ pub const ECHILD: c_int = 10;
+ pub const EDEADLK: c_int = 11;
+ pub const ENOMEM: c_int = 12;
+ pub const EACCES: c_int = 13;
+ pub const EFAULT: c_int = 14;
+ pub const ENOTBLK: c_int = 15;
+ pub const EBUSY: c_int = 16;
+ pub const EEXIST: c_int = 17;
+ pub const EXDEV: c_int = 18;
+ pub const ENODEV: c_int = 19;
+ pub const ENOTDIR: c_int = 20;
+ pub const EISDIR: c_int = 21;
+ pub const EINVAL: c_int = 22;
+ pub const ENFILE: c_int = 23;
+ pub const EMFILE: c_int = 24;
+ pub const ENOTTY: c_int = 25;
+ pub const ETXTBSY: c_int = 26;
+ pub const EFBIG: c_int = 27;
+ pub const ENOSPC: c_int = 28;
+ pub const ESPIPE: c_int = 29;
+ pub const EROFS: c_int = 30;
+ pub const EMLINK: c_int = 31;
+ pub const EPIPE: c_int = 32;
+ pub const EDOM: c_int = 33;
+ pub const ERANGE: c_int = 34;
+ pub const EAGAIN: c_int = 35;
+ pub const EWOULDBLOCK: c_int = 35;
+ pub const EINPROGRESS: c_int = 36;
+ pub const EALREADY: c_int = 37;
+ pub const ENOTSOCK: c_int = 38;
+ pub const EDESTADDRREQ: c_int = 39;
+ pub const EMSGSIZE: c_int = 40;
+ pub const EPROTOTYPE: c_int = 41;
+ pub const ENOPROTOOPT: c_int = 42;
+ pub const EPROTONOSUPPORT: c_int = 43;
+ pub const ESOCKTNOSUPPORT: c_int = 44;
+ pub const EOPNOTSUPP: c_int = 45;
+ pub const EPFNOSUPPORT: c_int = 46;
+ pub const EAFNOSUPPORT: c_int = 47;
+ pub const EADDRINUSE: c_int = 48;
+ pub const EADDRNOTAVAIL: c_int = 49;
+ pub const ENETDOWN: c_int = 50;
+ pub const ENETUNREACH: c_int = 51;
+ pub const ENETRESET: c_int = 52;
+ pub const ECONNABORTED: c_int = 53;
+ pub const ECONNRESET: c_int = 54;
+ pub const ENOBUFS: c_int = 55;
+ pub const EISCONN: c_int = 56;
+ pub const ENOTCONN: c_int = 57;
+ pub const ESHUTDOWN: c_int = 58;
+ pub const ETOOMANYREFS: c_int = 59;
+ pub const ETIMEDOUT: c_int = 60;
+ pub const ECONNREFUSED: c_int = 61;
+ pub const ELOOP: c_int = 62;
+ pub const ENAMETOOLONG: c_int = 63;
+ pub const EHOSTDOWN: c_int = 64;
+ pub const EHOSTUNREACH: c_int = 65;
+ pub const ENOTEMPTY: c_int = 66;
+ pub const EPROCLIM: c_int = 67;
+ pub const EUSERS: c_int = 68;
+ pub const EDQUOT: c_int = 69;
+ pub const ESTALE: c_int = 70;
+ pub const EREMOTE: c_int = 71;
+ pub const EBADRPC: c_int = 72;
+ pub const ERPCMISMATCH: c_int = 73;
+ pub const EPROGUNAVAIL: c_int = 74;
+ pub const EPROGMISMATCH: c_int = 75;
+ pub const EPROCUNAVAIL: c_int = 76;
+ pub const ENOLCK: c_int = 77;
+ pub const ENOSYS: c_int = 78;
+ pub const EFTYPE: c_int = 79;
+ pub const EAUTH: c_int = 80;
+ pub const ENEEDAUTH: c_int = 81;
+ pub const EIDRM: c_int = 82;
+ pub const ENOMSG: c_int = 83;
+ pub const EOVERFLOW: c_int = 84;
+ pub const ECANCELED: c_int = 85;
+ pub const EILSEQ: c_int = 86;
+ pub const ENOATTR: c_int = 87;
+ pub const EDOOFUS: c_int = 88;
+ pub const EBADMSG: c_int = 89;
+ pub const EMULTIHOP: c_int = 90;
+ pub const ENOLINK: c_int = 91;
+ pub const EPROTO: c_int = 92;
+ pub const ENOMEDIUM: c_int = 93;
+ pub const EUNUSED94: c_int = 94;
+ pub const EUNUSED95: c_int = 95;
+ pub const EUNUSED96: c_int = 96;
+ pub const EUNUSED97: c_int = 97;
+ pub const EUNUSED98: c_int = 98;
+ pub const EASYNC: c_int = 99;
+ pub const ELAST: c_int = 99;
}
pub mod posix01 {
use types::os::arch::c95::{c_int, size_t};
use types::os::common::posix01::rlim_t;
- pub const F_DUPFD : c_int = 0;
- pub const F_GETFD : c_int = 1;
- pub const F_SETFD : c_int = 2;
- pub const F_GETFL : c_int = 3;
- pub const F_SETFL : c_int = 4;
+ pub const F_DUPFD: c_int = 0;
+ pub const F_GETFD: c_int = 1;
+ pub const F_SETFD: c_int = 2;
+ pub const F_GETFL: c_int = 3;
+ pub const F_SETFL: c_int = 4;
- pub const SIGTRAP : c_int = 5;
+ pub const SIGTRAP: c_int = 5;
pub const SIG_IGN: size_t = 1;
- pub const GLOB_APPEND : c_int = 0x0001;
- pub const GLOB_DOOFFS : c_int = 0x0002;
- pub const GLOB_ERR : c_int = 0x0004;
- pub const GLOB_MARK : c_int = 0x0008;
- pub const GLOB_NOCHECK : c_int = 0x0010;
- pub const GLOB_NOSORT : c_int = 0x0020;
- pub const GLOB_NOESCAPE : c_int = 0x2000;
-
- pub const GLOB_NOSPACE : c_int = -1;
- pub const GLOB_ABORTED : c_int = -2;
- pub const GLOB_NOMATCH : c_int = -3;
-
- pub const POSIX_MADV_NORMAL : c_int = 0;
- pub const POSIX_MADV_RANDOM : c_int = 1;
- pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
- pub const POSIX_MADV_WILLNEED : c_int = 3;
- pub const POSIX_MADV_DONTNEED : c_int = 4;
-
- pub const _SC_IOV_MAX : c_int = 56;
- pub const _SC_GETGR_R_SIZE_MAX : c_int = 70;
- pub const _SC_GETPW_R_SIZE_MAX : c_int = 71;
- pub const _SC_LOGIN_NAME_MAX : c_int = 73;
- pub const _SC_MQ_PRIO_MAX : c_int = 75;
- pub const _SC_THREAD_ATTR_STACKADDR : c_int = 82;
- pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 83;
- pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85;
- pub const _SC_THREAD_KEYS_MAX : c_int = 86;
- pub const _SC_THREAD_PRIO_INHERIT : c_int = 87;
- pub const _SC_THREAD_PRIO_PROTECT : c_int = 88;
- pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89;
- pub const _SC_THREAD_PROCESS_SHARED : c_int = 90;
- pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 91;
- pub const _SC_THREAD_STACK_MIN : c_int = 93;
- pub const _SC_THREAD_THREADS_MAX : c_int = 94;
- pub const _SC_THREADS : c_int = 96;
- pub const _SC_TTY_NAME_MAX : c_int = 101;
- pub const _SC_ATEXIT_MAX : c_int = 107;
- pub const _SC_XOPEN_CRYPT : c_int = 108;
- pub const _SC_XOPEN_ENH_I18N : c_int = 109;
- pub const _SC_XOPEN_LEGACY : c_int = 110;
- pub const _SC_XOPEN_REALTIME : c_int = 111;
- pub const _SC_XOPEN_REALTIME_THREADS : c_int = 112;
- pub const _SC_XOPEN_SHM : c_int = 113;
- pub const _SC_XOPEN_UNIX : c_int = 115;
- pub const _SC_XOPEN_VERSION : c_int = 116;
- pub const _SC_XOPEN_XCU_VERSION : c_int = 117;
+ pub const GLOB_APPEND: c_int = 0x0001;
+ pub const GLOB_DOOFFS: c_int = 0x0002;
+ pub const GLOB_ERR: c_int = 0x0004;
+ pub const GLOB_MARK: c_int = 0x0008;
+ pub const GLOB_NOCHECK: c_int = 0x0010;
+ pub const GLOB_NOSORT: c_int = 0x0020;
+ pub const GLOB_NOESCAPE: c_int = 0x2000;
+
+ pub const GLOB_NOSPACE: c_int = -1;
+ pub const GLOB_ABORTED: c_int = -2;
+ pub const GLOB_NOMATCH: c_int = -3;
+
+ pub const POSIX_MADV_NORMAL: c_int = 0;
+ pub const POSIX_MADV_RANDOM: c_int = 1;
+ pub const POSIX_MADV_SEQUENTIAL: c_int = 2;
+ pub const POSIX_MADV_WILLNEED: c_int = 3;
+ pub const POSIX_MADV_DONTNEED: c_int = 4;
+
+ pub const _SC_IOV_MAX: c_int = 56;
+ pub const _SC_GETGR_R_SIZE_MAX: c_int = 70;
+ pub const _SC_GETPW_R_SIZE_MAX: c_int = 71;
+ pub const _SC_LOGIN_NAME_MAX: c_int = 73;
+ pub const _SC_MQ_PRIO_MAX: c_int = 75;
+ pub const _SC_THREAD_ATTR_STACKADDR: c_int = 82;
+ pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 83;
+ pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 85;
+ pub const _SC_THREAD_KEYS_MAX: c_int = 86;
+ pub const _SC_THREAD_PRIO_INHERIT: c_int = 87;
+ pub const _SC_THREAD_PRIO_PROTECT: c_int = 88;
+ pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 89;
+ pub const _SC_THREAD_PROCESS_SHARED: c_int = 90;
+ pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 91;
+ pub const _SC_THREAD_STACK_MIN: c_int = 93;
+ pub const _SC_THREAD_THREADS_MAX: c_int = 94;
+ pub const _SC_THREADS: c_int = 96;
+ pub const _SC_TTY_NAME_MAX: c_int = 101;
+ pub const _SC_ATEXIT_MAX: c_int = 107;
+ pub const _SC_XOPEN_CRYPT: c_int = 108;
+ pub const _SC_XOPEN_ENH_I18N: c_int = 109;
+ pub const _SC_XOPEN_LEGACY: c_int = 110;
+ pub const _SC_XOPEN_REALTIME: c_int = 111;
+ pub const _SC_XOPEN_REALTIME_THREADS: c_int = 112;
+ pub const _SC_XOPEN_SHM: c_int = 113;
+ pub const _SC_XOPEN_UNIX: c_int = 115;
+ pub const _SC_XOPEN_VERSION: c_int = 116;
+ pub const _SC_XOPEN_XCU_VERSION: c_int = 117;
pub const PTHREAD_CREATE_JOINABLE: c_int = 0;
pub const PTHREAD_CREATE_DETACHED: c_int = 1;
pub mod bsd44 {
use types::os::arch::c95::c_int;
- pub const MADV_NORMAL : c_int = 0;
- pub const MADV_RANDOM : c_int = 1;
- pub const MADV_SEQUENTIAL : c_int = 2;
- pub const MADV_WILLNEED : c_int = 3;
- pub const MADV_DONTNEED : c_int = 4;
- pub const MADV_FREE : c_int = 5;
- pub const MADV_NOSYNC : c_int = 6;
- pub const MADV_AUTOSYNC : c_int = 7;
- pub const MADV_NOCORE : c_int = 8;
- pub const MADV_CORE : c_int = 9;
- pub const MADV_PROTECT : c_int = 10;
-
- pub const MINCORE_INCORE : c_int = 0x1;
- pub const MINCORE_REFERENCED : c_int = 0x2;
- pub const MINCORE_MODIFIED : c_int = 0x4;
- pub const MINCORE_REFERENCED_OTHER : c_int = 0x8;
- pub const MINCORE_MODIFIED_OTHER : c_int = 0x10;
- pub const MINCORE_SUPER : c_int = 0x20;
+ pub const MADV_NORMAL: c_int = 0;
+ pub const MADV_RANDOM: c_int = 1;
+ pub const MADV_SEQUENTIAL: c_int = 2;
+ pub const MADV_WILLNEED: c_int = 3;
+ pub const MADV_DONTNEED: c_int = 4;
+ pub const MADV_FREE: c_int = 5;
+ pub const MADV_NOSYNC: c_int = 6;
+ pub const MADV_AUTOSYNC: c_int = 7;
+ pub const MADV_NOCORE: c_int = 8;
+ pub const MADV_CORE: c_int = 9;
+ pub const MADV_PROTECT: c_int = 10;
+
+ pub const MINCORE_INCORE: c_int = 0x1;
+ pub const MINCORE_REFERENCED: c_int = 0x2;
+ pub const MINCORE_MODIFIED: c_int = 0x4;
+ pub const MINCORE_REFERENCED_OTHER: c_int = 0x8;
+ pub const MINCORE_MODIFIED_OTHER: c_int = 0x10;
+ pub const MINCORE_SUPER: c_int = 0x20;
pub const AF_INET: c_int = 2;
pub const AF_INET6: c_int = 28;
pub mod extra {
use types::os::arch::c95::c_int;
- pub const O_SYNC : c_int = 128;
- pub const O_NONBLOCK : c_int = 4;
+ pub const O_SYNC: c_int = 128;
+ pub const O_NONBLOCK: c_int = 4;
pub const CTL_KERN: c_int = 1;
pub const KERN_PROC: c_int = 14;
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "dragonfly")]
pub const KERN_PROC_PATHNAME: c_int = 9;
- pub const MAP_COPY : c_int = 0x0002;
- pub const MAP_RENAME : c_int = 0x0020;
- pub const MAP_NORESERVE : c_int = 0x0040;
- pub const MAP_HASSEMAPHORE : c_int = 0x0200;
- pub const MAP_STACK : c_int = 0x0400;
- pub const MAP_NOSYNC : c_int = 0x0800;
- pub const MAP_NOCORE : c_int = 0x020000;
+ pub const MAP_COPY: c_int = 0x0002;
+ pub const MAP_RENAME: c_int = 0x0020;
+ pub const MAP_NORESERVE: c_int = 0x0040;
+ pub const MAP_HASSEMAPHORE: c_int = 0x0200;
+ pub const MAP_STACK: c_int = 0x0400;
+ pub const MAP_NOSYNC: c_int = 0x0800;
+ pub const MAP_NOCORE: c_int = 0x020000;
- pub const IPPROTO_RAW : c_int = 255;
+ pub const IPPROTO_RAW: c_int = 255;
}
pub mod sysconf {
use types::os::arch::c95::c_int;
- pub const _SC_ARG_MAX : c_int = 1;
- pub const _SC_CHILD_MAX : c_int = 2;
- pub const _SC_CLK_TCK : c_int = 3;
- pub const _SC_NGROUPS_MAX : c_int = 4;
- pub const _SC_OPEN_MAX : c_int = 5;
- pub const _SC_JOB_CONTROL : c_int = 6;
- pub const _SC_SAVED_IDS : c_int = 7;
- pub const _SC_VERSION : c_int = 8;
- pub const _SC_BC_BASE_MAX : c_int = 9;
- pub const _SC_BC_DIM_MAX : c_int = 10;
- pub const _SC_BC_SCALE_MAX : c_int = 11;
- pub const _SC_BC_STRING_MAX : c_int = 12;
- pub const _SC_COLL_WEIGHTS_MAX : c_int = 13;
- pub const _SC_EXPR_NEST_MAX : c_int = 14;
- pub const _SC_LINE_MAX : c_int = 15;
- pub const _SC_RE_DUP_MAX : c_int = 16;
- pub const _SC_2_VERSION : c_int = 17;
- pub const _SC_2_C_BIND : c_int = 18;
- pub const _SC_2_C_DEV : c_int = 19;
- pub const _SC_2_CHAR_TERM : c_int = 20;
- pub const _SC_2_FORT_DEV : c_int = 21;
- pub const _SC_2_FORT_RUN : c_int = 22;
- pub const _SC_2_LOCALEDEF : c_int = 23;
- pub const _SC_2_SW_DEV : c_int = 24;
- pub const _SC_2_UPE : c_int = 25;
- pub const _SC_STREAM_MAX : c_int = 26;
- pub const _SC_TZNAME_MAX : c_int = 27;
- pub const _SC_ASYNCHRONOUS_IO : c_int = 28;
- pub const _SC_MAPPED_FILES : c_int = 29;
- pub const _SC_MEMLOCK : c_int = 30;
- pub const _SC_MEMLOCK_RANGE : c_int = 31;
- pub const _SC_MEMORY_PROTECTION : c_int = 32;
- pub const _SC_MESSAGE_PASSING : c_int = 33;
- pub const _SC_PRIORITIZED_IO : c_int = 34;
- pub const _SC_PRIORITY_SCHEDULING : c_int = 35;
- pub const _SC_REALTIME_SIGNALS : c_int = 36;
- pub const _SC_SEMAPHORES : c_int = 37;
- pub const _SC_FSYNC : c_int = 38;
- pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 39;
- pub const _SC_SYNCHRONIZED_IO : c_int = 40;
- pub const _SC_TIMERS : c_int = 41;
- pub const _SC_AIO_LISTIO_MAX : c_int = 42;
- pub const _SC_AIO_MAX : c_int = 43;
- pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44;
- pub const _SC_DELAYTIMER_MAX : c_int = 45;
- pub const _SC_MQ_OPEN_MAX : c_int = 46;
- pub const _SC_PAGESIZE : c_int = 47;
- pub const _SC_RTSIG_MAX : c_int = 48;
- pub const _SC_SEM_NSEMS_MAX : c_int = 49;
- pub const _SC_SEM_VALUE_MAX : c_int = 50;
- pub const _SC_SIGQUEUE_MAX : c_int = 51;
- pub const _SC_TIMER_MAX : c_int = 52;
+ pub const _SC_ARG_MAX: c_int = 1;
+ pub const _SC_CHILD_MAX: c_int = 2;
+ pub const _SC_CLK_TCK: c_int = 3;
+ pub const _SC_NGROUPS_MAX: c_int = 4;
+ pub const _SC_OPEN_MAX: c_int = 5;
+ pub const _SC_JOB_CONTROL: c_int = 6;
+ pub const _SC_SAVED_IDS: c_int = 7;
+ pub const _SC_VERSION: c_int = 8;
+ pub const _SC_BC_BASE_MAX: c_int = 9;
+ pub const _SC_BC_DIM_MAX: c_int = 10;
+ pub const _SC_BC_SCALE_MAX: c_int = 11;
+ pub const _SC_BC_STRING_MAX: c_int = 12;
+ pub const _SC_COLL_WEIGHTS_MAX: c_int = 13;
+ pub const _SC_EXPR_NEST_MAX: c_int = 14;
+ pub const _SC_LINE_MAX: c_int = 15;
+ pub const _SC_RE_DUP_MAX: c_int = 16;
+ pub const _SC_2_VERSION: c_int = 17;
+ pub const _SC_2_C_BIND: c_int = 18;
+ pub const _SC_2_C_DEV: c_int = 19;
+ pub const _SC_2_CHAR_TERM: c_int = 20;
+ pub const _SC_2_FORT_DEV: c_int = 21;
+ pub const _SC_2_FORT_RUN: c_int = 22;
+ pub const _SC_2_LOCALEDEF: c_int = 23;
+ pub const _SC_2_SW_DEV: c_int = 24;
+ pub const _SC_2_UPE: c_int = 25;
+ pub const _SC_STREAM_MAX: c_int = 26;
+ pub const _SC_TZNAME_MAX: c_int = 27;
+ pub const _SC_ASYNCHRONOUS_IO: c_int = 28;
+ pub const _SC_MAPPED_FILES: c_int = 29;
+ pub const _SC_MEMLOCK: c_int = 30;
+ pub const _SC_MEMLOCK_RANGE: c_int = 31;
+ pub const _SC_MEMORY_PROTECTION: c_int = 32;
+ pub const _SC_MESSAGE_PASSING: c_int = 33;
+ pub const _SC_PRIORITIZED_IO: c_int = 34;
+ pub const _SC_PRIORITY_SCHEDULING: c_int = 35;
+ pub const _SC_REALTIME_SIGNALS: c_int = 36;
+ pub const _SC_SEMAPHORES: c_int = 37;
+ pub const _SC_FSYNC: c_int = 38;
+ pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 39;
+ pub const _SC_SYNCHRONIZED_IO: c_int = 40;
+ pub const _SC_TIMERS: c_int = 41;
+ pub const _SC_AIO_LISTIO_MAX: c_int = 42;
+ pub const _SC_AIO_MAX: c_int = 43;
+ pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44;
+ pub const _SC_DELAYTIMER_MAX: c_int = 45;
+ pub const _SC_MQ_OPEN_MAX: c_int = 46;
+ pub const _SC_PAGESIZE: c_int = 47;
+ pub const _SC_RTSIG_MAX: c_int = 48;
+ pub const _SC_SEM_NSEMS_MAX: c_int = 49;
+ pub const _SC_SEM_VALUE_MAX: c_int = 50;
+ pub const _SC_SIGQUEUE_MAX: c_int = 51;
+ pub const _SC_TIMER_MAX: c_int = 52;
pub const _PC_NAME_MAX: c_int = 4;
pub const _PC_PATH_MAX: c_int = 5;
}
}
- #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))]
+ #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
pub mod os {
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
- pub const EXIT_FAILURE : c_int = 1;
- pub const EXIT_SUCCESS : c_int = 0;
- pub const RAND_MAX : c_int = 2147483647;
- pub const EOF : c_int = -1;
- pub const SEEK_SET : c_int = 0;
- pub const SEEK_CUR : c_int = 1;
- pub const SEEK_END : c_int = 2;
- pub const _IOFBF : c_int = 0;
- pub const _IONBF : c_int = 2;
- pub const _IOLBF : c_int = 1;
- pub const BUFSIZ : c_uint = 1024;
- pub const FOPEN_MAX : c_uint = 20;
- pub const FILENAME_MAX : c_uint = 1024;
- pub const L_tmpnam : c_uint = 1024;
- pub const TMP_MAX : c_uint = 308915776;
+ pub const EXIT_FAILURE: c_int = 1;
+ pub const EXIT_SUCCESS: c_int = 0;
+ pub const RAND_MAX: c_int = 2147483647;
+ pub const EOF: c_int = -1;
+ pub const SEEK_SET: c_int = 0;
+ pub const SEEK_CUR: c_int = 1;
+ pub const SEEK_END: c_int = 2;
+ pub const _IOFBF: c_int = 0;
+ pub const _IONBF: c_int = 2;
+ pub const _IOLBF: c_int = 1;
+ pub const BUFSIZ: c_uint = 1024;
+ pub const FOPEN_MAX: c_uint = 20;
+ pub const FILENAME_MAX: c_uint = 1024;
+ pub const L_tmpnam: c_uint = 1024;
+ pub const TMP_MAX: c_uint = 308915776;
}
pub mod c99 {
}
use types::os::arch::c95::c_int;
use types::os::arch::posix88::mode_t;
- pub const O_RDONLY : c_int = 0;
- pub const O_WRONLY : c_int = 1;
- pub const O_RDWR : c_int = 2;
- pub const O_APPEND : c_int = 8;
- pub const O_CREAT : c_int = 512;
- pub const O_EXCL : c_int = 2048;
- pub const O_NOCTTY : c_int = 32768;
- pub const O_TRUNC : c_int = 1024;
- pub const S_IFIFO : mode_t = 4096;
- pub const S_IFCHR : mode_t = 8192;
- pub const S_IFBLK : mode_t = 24576;
- pub const S_IFDIR : mode_t = 16384;
- pub const S_IFREG : mode_t = 32768;
- pub const S_IFLNK : mode_t = 40960;
- pub const S_IFSOCK : mode_t = 49152;
- pub const S_IFMT : mode_t = 61440;
- pub const S_IEXEC : mode_t = 64;
- pub const S_IWRITE : mode_t = 128;
- pub const S_IREAD : mode_t = 256;
- pub const S_IRWXU : mode_t = 448;
- pub const S_IXUSR : mode_t = 64;
- pub const S_IWUSR : mode_t = 128;
- pub const S_IRUSR : mode_t = 256;
- pub const S_IRWXG : mode_t = 56;
- pub const S_IXGRP : mode_t = 8;
- pub const S_IWGRP : mode_t = 16;
- pub const S_IRGRP : mode_t = 32;
- pub const S_IRWXO : mode_t = 7;
- pub const S_IXOTH : mode_t = 1;
- pub const S_IWOTH : mode_t = 2;
- pub const S_IROTH : mode_t = 4;
- pub const F_OK : c_int = 0;
- pub const R_OK : c_int = 4;
- pub const W_OK : c_int = 2;
- pub const X_OK : c_int = 1;
- pub const STDIN_FILENO : c_int = 0;
- pub const STDOUT_FILENO : c_int = 1;
- pub const STDERR_FILENO : c_int = 2;
- pub const F_LOCK : c_int = 1;
- pub const F_TEST : c_int = 3;
- pub const F_TLOCK : c_int = 2;
- pub const F_ULOCK : c_int = 0;
- pub const SIGHUP : c_int = 1;
- pub const SIGINT : c_int = 2;
- pub const SIGQUIT : c_int = 3;
- pub const SIGILL : c_int = 4;
- pub const SIGABRT : c_int = 6;
- pub const SIGFPE : c_int = 8;
- pub const SIGKILL : c_int = 9;
- pub const SIGSEGV : c_int = 11;
- pub const SIGPIPE : c_int = 13;
- pub const SIGALRM : c_int = 14;
- pub const SIGTERM : c_int = 15;
-
- pub const PROT_NONE : c_int = 0;
- pub const PROT_READ : c_int = 1;
- pub const PROT_WRITE : c_int = 2;
- pub const PROT_EXEC : c_int = 4;
-
- pub const MAP_FILE : c_int = 0x0000;
- pub const MAP_SHARED : c_int = 0x0001;
- pub const MAP_PRIVATE : c_int = 0x0002;
- pub const MAP_FIXED : c_int = 0x0010;
- pub const MAP_ANON : c_int = 0x1000;
-
- pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
-
- pub const MCL_CURRENT : c_int = 0x0001;
- pub const MCL_FUTURE : c_int = 0x0002;
-
- pub const MS_ASYNC : c_int = 0x0001;
- pub const MS_SYNC : c_int = 0x0002;
- pub const MS_INVALIDATE : c_int = 0x0004;
-
- pub const EPERM : c_int = 1;
- pub const ENOENT : c_int = 2;
- pub const ESRCH : c_int = 3;
- pub const EINTR : c_int = 4;
- pub const EIO : c_int = 5;
- pub const ENXIO : c_int = 6;
- pub const E2BIG : c_int = 7;
- pub const ENOEXEC : c_int = 8;
- pub const EBADF : c_int = 9;
- pub const ECHILD : c_int = 10;
- pub const EDEADLK : c_int = 11;
- pub const ENOMEM : c_int = 12;
- pub const EACCES : c_int = 13;
- pub const EFAULT : c_int = 14;
- pub const ENOTBLK : c_int = 15;
- pub const EBUSY : c_int = 16;
- pub const EEXIST : c_int = 17;
- pub const EXDEV : c_int = 18;
- pub const ENODEV : c_int = 19;
- pub const ENOTDIR : c_int = 20;
- pub const EISDIR : c_int = 21;
- pub const EINVAL : c_int = 22;
- pub const ENFILE : c_int = 23;
- pub const EMFILE : c_int = 24;
- pub const ENOTTY : c_int = 25;
- pub const ETXTBSY : c_int = 26;
- pub const EFBIG : c_int = 27;
- pub const ENOSPC : c_int = 28;
- pub const ESPIPE : c_int = 29;
- pub const EROFS : c_int = 30;
- pub const EMLINK : c_int = 31;
- pub const EPIPE : c_int = 32;
- pub const EDOM : c_int = 33;
- pub const ERANGE : c_int = 34;
- pub const EAGAIN : c_int = 35;
- pub const EWOULDBLOCK : c_int = 35;
- pub const EINPROGRESS : c_int = 36;
- pub const EALREADY : c_int = 37;
- pub const ENOTSOCK : c_int = 38;
- pub const EDESTADDRREQ : c_int = 39;
- pub const EMSGSIZE : c_int = 40;
- pub const EPROTOTYPE : c_int = 41;
- pub const ENOPROTOOPT : c_int = 42;
- pub const EPROTONOSUPPORT : c_int = 43;
- pub const ESOCKTNOSUPPORT : c_int = 44;
- pub const EOPNOTSUPP : c_int = 45;
- pub const EPFNOSUPPORT : c_int = 46;
- pub const EAFNOSUPPORT : c_int = 47;
- pub const EADDRINUSE : c_int = 48;
- pub const EADDRNOTAVAIL : c_int = 49;
- pub const ENETDOWN : c_int = 50;
- pub const ENETUNREACH : c_int = 51;
- pub const ENETRESET : c_int = 52;
- pub const ECONNABORTED : c_int = 53;
- pub const ECONNRESET : c_int = 54;
- pub const ENOBUFS : c_int = 55;
- pub const EISCONN : c_int = 56;
- pub const ENOTCONN : c_int = 57;
- pub const ESHUTDOWN : c_int = 58;
- pub const ETOOMANYREFS : c_int = 59;
- pub const ETIMEDOUT : c_int = 60;
- pub const ECONNREFUSED : c_int = 61;
- pub const ELOOP : c_int = 62;
- pub const ENAMETOOLONG : c_int = 63;
- pub const EHOSTDOWN : c_int = 64;
- pub const EHOSTUNREACH : c_int = 65;
- pub const ENOTEMPTY : c_int = 66;
- pub const EPROCLIM : c_int = 67;
- pub const EUSERS : c_int = 68;
- pub const EDQUOT : c_int = 69;
- pub const ESTALE : c_int = 70;
- pub const EREMOTE : c_int = 71;
- pub const EBADRPC : c_int = 72;
- pub const ERPCMISMATCH : c_int = 73;
- pub const EPROGUNAVAIL : c_int = 74;
- pub const EPROGMISMATCH : c_int = 75;
- pub const EPROCUNAVAIL : c_int = 76;
- pub const ENOLCK : c_int = 77;
- pub const ENOSYS : c_int = 78;
- pub const EFTYPE : c_int = 79;
- pub const EAUTH : c_int = 80;
- pub const ENEEDAUTH : c_int = 81;
- pub const EIPSEC : c_int = 82;
- pub const ENOATTR : c_int = 83;
- pub const EILSEQ : c_int = 84;
- pub const ENOMEDIUM : c_int = 85;
- pub const EMEDIUMTYPE : c_int = 86;
- pub const EOVERFLOW : c_int = 87;
- pub const ECANCELED : c_int = 88;
- pub const EIDRM : c_int = 89;
- pub const ENOMSG : c_int = 90;
- pub const ENOTSUP : c_int = 91;
- pub const ELAST : c_int = 91; // must be equal to largest errno
+ pub const O_RDONLY: c_int = 0;
+ pub const O_WRONLY: c_int = 1;
+ pub const O_RDWR: c_int = 2;
+ pub const O_APPEND: c_int = 8;
+ pub const O_CREAT: c_int = 512;
+ pub const O_EXCL: c_int = 2048;
+ pub const O_NOCTTY: c_int = 32768;
+ pub const O_TRUNC: c_int = 1024;
+ pub const S_IFIFO: mode_t = 4096;
+ pub const S_IFCHR: mode_t = 8192;
+ pub const S_IFBLK: mode_t = 24576;
+ pub const S_IFDIR: mode_t = 16384;
+ pub const S_IFREG: mode_t = 32768;
+ pub const S_IFLNK: mode_t = 40960;
+ pub const S_IFSOCK: mode_t = 49152;
+ pub const S_IFMT: mode_t = 61440;
+ pub const S_IEXEC: mode_t = 64;
+ pub const S_IWRITE: mode_t = 128;
+ pub const S_IREAD: mode_t = 256;
+ pub const S_IRWXU: mode_t = 448;
+ pub const S_IXUSR: mode_t = 64;
+ pub const S_IWUSR: mode_t = 128;
+ pub const S_IRUSR: mode_t = 256;
+ pub const S_IRWXG: mode_t = 56;
+ pub const S_IXGRP: mode_t = 8;
+ pub const S_IWGRP: mode_t = 16;
+ pub const S_IRGRP: mode_t = 32;
+ pub const S_IRWXO: mode_t = 7;
+ pub const S_IXOTH: mode_t = 1;
+ pub const S_IWOTH: mode_t = 2;
+ pub const S_IROTH: mode_t = 4;
+ pub const F_OK: c_int = 0;
+ pub const R_OK: c_int = 4;
+ pub const W_OK: c_int = 2;
+ pub const X_OK: c_int = 1;
+ pub const STDIN_FILENO: c_int = 0;
+ pub const STDOUT_FILENO: c_int = 1;
+ pub const STDERR_FILENO: c_int = 2;
+ pub const F_LOCK: c_int = 1;
+ pub const F_TEST: c_int = 3;
+ pub const F_TLOCK: c_int = 2;
+ pub const F_ULOCK: c_int = 0;
+ pub const SIGHUP: c_int = 1;
+ pub const SIGINT: c_int = 2;
+ pub const SIGQUIT: c_int = 3;
+ pub const SIGILL: c_int = 4;
+ pub const SIGABRT: c_int = 6;
+ pub const SIGFPE: c_int = 8;
+ pub const SIGKILL: c_int = 9;
+ pub const SIGSEGV: c_int = 11;
+ pub const SIGPIPE: c_int = 13;
+ pub const SIGALRM: c_int = 14;
+ pub const SIGTERM: c_int = 15;
+
+ pub const PROT_NONE: c_int = 0;
+ pub const PROT_READ: c_int = 1;
+ pub const PROT_WRITE: c_int = 2;
+ pub const PROT_EXEC: c_int = 4;
+
+ pub const MAP_FILE: c_int = 0x0000;
+ pub const MAP_SHARED: c_int = 0x0001;
+ pub const MAP_PRIVATE: c_int = 0x0002;
+ pub const MAP_FIXED: c_int = 0x0010;
+ pub const MAP_ANON: c_int = 0x1000;
+
+ pub const MAP_FAILED: *mut c_void = !0 as *mut c_void;
+
+ pub const MCL_CURRENT: c_int = 0x0001;
+ pub const MCL_FUTURE: c_int = 0x0002;
+
+ pub const MS_ASYNC: c_int = 0x0001;
+ pub const MS_SYNC: c_int = 0x0002;
+ pub const MS_INVALIDATE: c_int = 0x0004;
+
+ pub const EPERM: c_int = 1;
+ pub const ENOENT: c_int = 2;
+ pub const ESRCH: c_int = 3;
+ pub const EINTR: c_int = 4;
+ pub const EIO: c_int = 5;
+ pub const ENXIO: c_int = 6;
+ pub const E2BIG: c_int = 7;
+ pub const ENOEXEC: c_int = 8;
+ pub const EBADF: c_int = 9;
+ pub const ECHILD: c_int = 10;
+ pub const EDEADLK: c_int = 11;
+ pub const ENOMEM: c_int = 12;
+ pub const EACCES: c_int = 13;
+ pub const EFAULT: c_int = 14;
+ pub const ENOTBLK: c_int = 15;
+ pub const EBUSY: c_int = 16;
+ pub const EEXIST: c_int = 17;
+ pub const EXDEV: c_int = 18;
+ pub const ENODEV: c_int = 19;
+ pub const ENOTDIR: c_int = 20;
+ pub const EISDIR: c_int = 21;
+ pub const EINVAL: c_int = 22;
+ pub const ENFILE: c_int = 23;
+ pub const EMFILE: c_int = 24;
+ pub const ENOTTY: c_int = 25;
+ pub const ETXTBSY: c_int = 26;
+ pub const EFBIG: c_int = 27;
+ pub const ENOSPC: c_int = 28;
+ pub const ESPIPE: c_int = 29;
+ pub const EROFS: c_int = 30;
+ pub const EMLINK: c_int = 31;
+ pub const EPIPE: c_int = 32;
+ pub const EDOM: c_int = 33;
+ pub const ERANGE: c_int = 34;
+ pub const EAGAIN: c_int = 35;
+ pub const EWOULDBLOCK: c_int = 35;
+ pub const EINPROGRESS: c_int = 36;
+ pub const EALREADY: c_int = 37;
+ pub const ENOTSOCK: c_int = 38;
+ pub const EDESTADDRREQ: c_int = 39;
+ pub const EMSGSIZE: c_int = 40;
+ pub const EPROTOTYPE: c_int = 41;
+ pub const ENOPROTOOPT: c_int = 42;
+ pub const EPROTONOSUPPORT: c_int = 43;
+ pub const ESOCKTNOSUPPORT: c_int = 44;
+ pub const EOPNOTSUPP: c_int = 45;
+ pub const EPFNOSUPPORT: c_int = 46;
+ pub const EAFNOSUPPORT: c_int = 47;
+ pub const EADDRINUSE: c_int = 48;
+ pub const EADDRNOTAVAIL: c_int = 49;
+ pub const ENETDOWN: c_int = 50;
+ pub const ENETUNREACH: c_int = 51;
+ pub const ENETRESET: c_int = 52;
+ pub const ECONNABORTED: c_int = 53;
+ pub const ECONNRESET: c_int = 54;
+ pub const ENOBUFS: c_int = 55;
+ pub const EISCONN: c_int = 56;
+ pub const ENOTCONN: c_int = 57;
+ pub const ESHUTDOWN: c_int = 58;
+ pub const ETOOMANYREFS: c_int = 59;
+ pub const ETIMEDOUT: c_int = 60;
+ pub const ECONNREFUSED: c_int = 61;
+ pub const ELOOP: c_int = 62;
+ pub const ENAMETOOLONG: c_int = 63;
+ pub const EHOSTDOWN: c_int = 64;
+ pub const EHOSTUNREACH: c_int = 65;
+ pub const ENOTEMPTY: c_int = 66;
+ pub const EPROCLIM: c_int = 67;
+ pub const EUSERS: c_int = 68;
+ pub const EDQUOT: c_int = 69;
+ pub const ESTALE: c_int = 70;
+ pub const EREMOTE: c_int = 71;
+ pub const EBADRPC: c_int = 72;
+ pub const ERPCMISMATCH: c_int = 73;
+ pub const EPROGUNAVAIL: c_int = 74;
+ pub const EPROGMISMATCH: c_int = 75;
+ pub const EPROCUNAVAIL: c_int = 76;
+ pub const ENOLCK: c_int = 77;
+ pub const ENOSYS: c_int = 78;
+ pub const EFTYPE: c_int = 79;
+ pub const EAUTH: c_int = 80;
+ pub const ENEEDAUTH: c_int = 81;
+ pub const EIPSEC: c_int = 82;
+ pub const ENOATTR: c_int = 83;
+ pub const EILSEQ: c_int = 84;
+ pub const ENOMEDIUM: c_int = 85;
+ pub const EMEDIUMTYPE: c_int = 86;
+ pub const EOVERFLOW: c_int = 87;
+ pub const ECANCELED: c_int = 88;
+ pub const EIDRM: c_int = 89;
+ pub const ENOMSG: c_int = 90;
+ pub const ENOTSUP: c_int = 91;
+ pub const ELAST: c_int = 91; // must be equal to largest errno
}
pub mod posix01 {
use types::os::arch::c95::{c_int, size_t};
use types::os::common::posix01::rlim_t;
- pub const F_DUPFD : c_int = 0;
- pub const F_GETFD : c_int = 1;
- pub const F_SETFD : c_int = 2;
- pub const F_GETFL : c_int = 3;
- pub const F_SETFL : c_int = 4;
- pub const F_GETOWN : c_int = 5;
- pub const F_SETOWN : c_int = 6;
- pub const F_GETLK : c_int = 7;
- pub const F_SETLK : c_int = 8;
- pub const F_SETLKW : c_int = 9;
-
- pub const SIGTRAP : c_int = 5;
+ pub const F_DUPFD: c_int = 0;
+ pub const F_GETFD: c_int = 1;
+ pub const F_SETFD: c_int = 2;
+ pub const F_GETFL: c_int = 3;
+ pub const F_SETFL: c_int = 4;
+ pub const F_GETOWN: c_int = 5;
+ pub const F_SETOWN: c_int = 6;
+ pub const F_GETLK: c_int = 7;
+ pub const F_SETLK: c_int = 8;
+ pub const F_SETLKW: c_int = 9;
+
+ pub const SIGTRAP: c_int = 5;
pub const SIG_IGN: size_t = 1;
- pub const GLOB_APPEND : c_int = 0x0001;
- pub const GLOB_DOOFFS : c_int = 0x0002;
- pub const GLOB_ERR : c_int = 0x0004;
- pub const GLOB_MARK : c_int = 0x0008;
- pub const GLOB_NOCHECK : c_int = 0x0010;
- pub const GLOB_NOSORT : c_int = 0x0020;
- pub const GLOB_NOESCAPE : c_int = 0x1000;
-
- pub const GLOB_NOSPACE : c_int = -1;
- pub const GLOB_ABORTED : c_int = -2;
- pub const GLOB_NOMATCH : c_int = -3;
- pub const GLOB_NOSYS : c_int = -4;
-
- pub const POSIX_MADV_NORMAL : c_int = 0;
- pub const POSIX_MADV_RANDOM : c_int = 1;
- pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
- pub const POSIX_MADV_WILLNEED : c_int = 3;
- pub const POSIX_MADV_DONTNEED : c_int = 4;
-
- pub const _SC_IOV_MAX : c_int = 51;
- pub const _SC_GETGR_R_SIZE_MAX : c_int = 100;
- pub const _SC_GETPW_R_SIZE_MAX : c_int = 101;
- pub const _SC_LOGIN_NAME_MAX : c_int = 102;
- pub const _SC_MQ_PRIO_MAX : c_int = 59;
- pub const _SC_THREAD_ATTR_STACKADDR : c_int = 77;
- pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 78;
- pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 80;
- pub const _SC_THREAD_KEYS_MAX : c_int = 81;
- pub const _SC_THREAD_PRIO_INHERIT : c_int = 82;
- pub const _SC_THREAD_PRIO_PROTECT : c_int = 83;
- pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 84;
- pub const _SC_THREAD_PROCESS_SHARED : c_int = 85;
- pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 103;
- pub const _SC_THREAD_STACK_MIN : c_int = 89;
- pub const _SC_THREAD_THREADS_MAX : c_int = 90;
- pub const _SC_THREADS : c_int = 91;
- pub const _SC_TTY_NAME_MAX : c_int = 107;
- pub const _SC_ATEXIT_MAX : c_int = 46;
- pub const _SC_XOPEN_CRYPT : c_int = 117;
- pub const _SC_XOPEN_ENH_I18N : c_int = 118;
- pub const _SC_XOPEN_LEGACY : c_int = 119;
- pub const _SC_XOPEN_REALTIME : c_int = 120;
- pub const _SC_XOPEN_REALTIME_THREADS : c_int = 121;
- pub const _SC_XOPEN_SHM : c_int = 30;
- pub const _SC_XOPEN_UNIX : c_int = 123;
- pub const _SC_XOPEN_VERSION : c_int = 125;
-
- pub const PTHREAD_CREATE_JOINABLE : c_int = 0;
- pub const PTHREAD_CREATE_DETACHED : c_int = 1;
- pub const PTHREAD_STACK_MIN : size_t = 2048;
-
- pub const CLOCK_REALTIME : c_int = 0;
- pub const CLOCK_MONOTONIC : c_int = 3;
+ pub const GLOB_APPEND: c_int = 0x0001;
+ pub const GLOB_DOOFFS: c_int = 0x0002;
+ pub const GLOB_ERR: c_int = 0x0004;
+ pub const GLOB_MARK: c_int = 0x0008;
+ pub const GLOB_NOCHECK: c_int = 0x0010;
+ pub const GLOB_NOSORT: c_int = 0x0020;
+ pub const GLOB_NOESCAPE: c_int = 0x1000;
+
+ pub const GLOB_NOSPACE: c_int = -1;
+ pub const GLOB_ABORTED: c_int = -2;
+ pub const GLOB_NOMATCH: c_int = -3;
+ pub const GLOB_NOSYS: c_int = -4;
+
+ pub const POSIX_MADV_NORMAL: c_int = 0;
+ pub const POSIX_MADV_RANDOM: c_int = 1;
+ pub const POSIX_MADV_SEQUENTIAL: c_int = 2;
+ pub const POSIX_MADV_WILLNEED: c_int = 3;
+ pub const POSIX_MADV_DONTNEED: c_int = 4;
+
+ pub const _SC_IOV_MAX: c_int = 51;
+ pub const _SC_GETGR_R_SIZE_MAX: c_int = 100;
+ pub const _SC_GETPW_R_SIZE_MAX: c_int = 101;
+ pub const _SC_LOGIN_NAME_MAX: c_int = 102;
+ pub const _SC_MQ_PRIO_MAX: c_int = 59;
+ pub const _SC_THREAD_ATTR_STACKADDR: c_int = 77;
+ pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 78;
+ pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 80;
+ pub const _SC_THREAD_KEYS_MAX: c_int = 81;
+ pub const _SC_THREAD_PRIO_INHERIT: c_int = 82;
+ pub const _SC_THREAD_PRIO_PROTECT: c_int = 83;
+ pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 84;
+ pub const _SC_THREAD_PROCESS_SHARED: c_int = 85;
+ pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 103;
+ pub const _SC_THREAD_STACK_MIN: c_int = 89;
+ pub const _SC_THREAD_THREADS_MAX: c_int = 90;
+ pub const _SC_THREADS: c_int = 91;
+ pub const _SC_TTY_NAME_MAX: c_int = 107;
+ pub const _SC_ATEXIT_MAX: c_int = 46;
+ pub const _SC_XOPEN_CRYPT: c_int = 117;
+ pub const _SC_XOPEN_ENH_I18N: c_int = 118;
+ pub const _SC_XOPEN_LEGACY: c_int = 119;
+ pub const _SC_XOPEN_REALTIME: c_int = 120;
+ pub const _SC_XOPEN_REALTIME_THREADS: c_int = 121;
+ pub const _SC_XOPEN_SHM: c_int = 30;
+ pub const _SC_XOPEN_UNIX: c_int = 123;
+ pub const _SC_XOPEN_VERSION: c_int = 125;
+
+ pub const PTHREAD_CREATE_JOINABLE: c_int = 0;
+ pub const PTHREAD_CREATE_DETACHED: c_int = 1;
+ pub const PTHREAD_STACK_MIN: size_t = 2048;
+
+ pub const CLOCK_REALTIME: c_int = 0;
+ pub const CLOCK_MONOTONIC: c_int = 3;
pub const RLIMIT_CPU: c_int = 0;
pub const RLIMIT_FSIZE: c_int = 1;
pub const RUSAGE_CHILDREN: c_int = -1;
pub const RUSAGE_THREAD: c_int = 1;
}
- #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
pub mod posix08 {
use types::os::arch::c95::c_int;
pub const O_CLOEXEC: c_int = 0x10000;
pub const F_DUPFD_CLOEXEC: c_int = 10;
}
- #[cfg(target_os = "netbsd")]
- pub mod posix08 {
- use types::os::arch::c95::c_int;
- pub const O_CLOEXEC: c_int = 0x400000;
- pub const F_DUPFD_CLOEXEC: c_int = 12;
- }
pub mod bsd44 {
use types::os::arch::c95::c_int;
- pub const MADV_NORMAL : c_int = 0;
- pub const MADV_RANDOM : c_int = 1;
- pub const MADV_SEQUENTIAL : c_int = 2;
- pub const MADV_WILLNEED : c_int = 3;
- pub const MADV_DONTNEED : c_int = 4;
- pub const MADV_FREE : c_int = 6;
+ pub const MADV_NORMAL: c_int = 0;
+ pub const MADV_RANDOM: c_int = 1;
+ pub const MADV_SEQUENTIAL: c_int = 2;
+ pub const MADV_WILLNEED: c_int = 3;
+ pub const MADV_DONTNEED: c_int = 4;
+ pub const MADV_FREE: c_int = 6;
pub const AF_UNIX: c_int = 1;
pub const AF_INET: c_int = 2;
pub mod extra {
use types::os::arch::c95::c_int;
- pub const O_DSYNC : c_int = 128; // same as SYNC
- pub const O_SYNC : c_int = 128;
- pub const O_NONBLOCK : c_int = 4;
- pub const CTL_KERN : c_int = 1;
- pub const KERN_PROC : c_int = 66;
+ pub const O_DSYNC: c_int = 128; // same as SYNC
+ pub const O_SYNC: c_int = 128;
+ pub const O_NONBLOCK: c_int = 4;
+ pub const CTL_KERN: c_int = 1;
+ pub const KERN_PROC: c_int = 66;
- pub const MAP_COPY : c_int = 0x0002;
- pub const MAP_RENAME : c_int = 0x0000;
- pub const MAP_NORESERVE : c_int = 0x0000;
- pub const MAP_NOEXTEND : c_int = 0x0000;
- pub const MAP_HASSEMAPHORE : c_int = 0x0000;
+ pub const MAP_COPY: c_int = 0x0002;
+ pub const MAP_RENAME: c_int = 0x0000;
+ pub const MAP_NORESERVE: c_int = 0x0000;
+ pub const MAP_NOEXTEND: c_int = 0x0000;
+ pub const MAP_HASSEMAPHORE: c_int = 0x0000;
- pub const IPPROTO_RAW : c_int = 255;
+ pub const IPPROTO_RAW: c_int = 255;
pub const PATH_MAX: c_int = 1024;
}
pub mod sysconf {
use types::os::arch::c95::c_int;
- pub const _SC_ARG_MAX : c_int = 1;
- pub const _SC_CHILD_MAX : c_int = 2;
- pub const _SC_CLK_TCK : c_int = 3;
- pub const _SC_NGROUPS_MAX : c_int = 4;
- pub const _SC_OPEN_MAX : c_int = 5;
- pub const _SC_JOB_CONTROL : c_int = 6;
- pub const _SC_SAVED_IDS : c_int = 7;
- pub const _SC_VERSION : c_int = 8;
- pub const _SC_BC_BASE_MAX : c_int = 9;
- pub const _SC_BC_DIM_MAX : c_int = 10;
- pub const _SC_BC_SCALE_MAX : c_int = 11;
- pub const _SC_BC_STRING_MAX : c_int = 12;
- pub const _SC_COLL_WEIGHTS_MAX : c_int = 13;
- pub const _SC_EXPR_NEST_MAX : c_int = 14;
- pub const _SC_LINE_MAX : c_int = 15;
- pub const _SC_RE_DUP_MAX : c_int = 16;
- pub const _SC_2_VERSION : c_int = 17;
- pub const _SC_2_C_BIND : c_int = 18;
- pub const _SC_2_C_DEV : c_int = 19;
- pub const _SC_2_CHAR_TERM : c_int = 20;
- pub const _SC_2_FORT_DEV : c_int = 21;
- pub const _SC_2_FORT_RUN : c_int = 22;
- pub const _SC_2_LOCALEDEF : c_int = 23;
- pub const _SC_2_SW_DEV : c_int = 24;
- pub const _SC_2_UPE : c_int = 25;
- pub const _SC_STREAM_MAX : c_int = 26;
- pub const _SC_TZNAME_MAX : c_int = 27;
- pub const _SC_PAGESIZE : c_int = 28;
- pub const _SC_FSYNC : c_int = 29;
- pub const _SC_SEM_NSEMS_MAX : c_int = 31;
- pub const _SC_SEM_VALUE_MAX : c_int = 32;
- pub const _SC_AIO_LISTIO_MAX : c_int = 42;
- pub const _SC_AIO_MAX : c_int = 43;
- pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44;
- pub const _SC_ASYNCHRONOUS_IO : c_int = 45;
- pub const _SC_DELAYTIMER_MAX : c_int = 50;
- pub const _SC_MAPPED_FILES : c_int = 53;
- pub const _SC_MEMLOCK : c_int = 54;
- pub const _SC_MEMLOCK_RANGE : c_int = 55;
- pub const _SC_MEMORY_PROTECTION : c_int = 56;
- pub const _SC_MESSAGE_PASSING : c_int = 57;
- pub const _SC_MQ_OPEN_MAX : c_int = 58;
- pub const _SC_PRIORITIZED_IO : c_int = 60;
- pub const _SC_PRIORITY_SCHEDULING : c_int = 61;
- pub const _SC_REALTIME_SIGNALS : c_int = 64;
- pub const _SC_RTSIG_MAX : c_int = 66;
- pub const _SC_SEMAPHORES : c_int = 67;
- pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 68;
- pub const _SC_SIGQUEUE_MAX : c_int = 70;
- pub const _SC_SYNCHRONIZED_IO : c_int = 75;
- pub const _SC_TIMER_MAX : c_int = 93;
- pub const _SC_TIMERS : c_int = 94;
+ pub const _SC_ARG_MAX: c_int = 1;
+ pub const _SC_CHILD_MAX: c_int = 2;
+ pub const _SC_CLK_TCK: c_int = 3;
+ pub const _SC_NGROUPS_MAX: c_int = 4;
+ pub const _SC_OPEN_MAX: c_int = 5;
+ pub const _SC_JOB_CONTROL: c_int = 6;
+ pub const _SC_SAVED_IDS: c_int = 7;
+ pub const _SC_VERSION: c_int = 8;
+ pub const _SC_BC_BASE_MAX: c_int = 9;
+ pub const _SC_BC_DIM_MAX: c_int = 10;
+ pub const _SC_BC_SCALE_MAX: c_int = 11;
+ pub const _SC_BC_STRING_MAX: c_int = 12;
+ pub const _SC_COLL_WEIGHTS_MAX: c_int = 13;
+ pub const _SC_EXPR_NEST_MAX: c_int = 14;
+ pub const _SC_LINE_MAX: c_int = 15;
+ pub const _SC_RE_DUP_MAX: c_int = 16;
+ pub const _SC_2_VERSION: c_int = 17;
+ pub const _SC_2_C_BIND: c_int = 18;
+ pub const _SC_2_C_DEV: c_int = 19;
+ pub const _SC_2_CHAR_TERM: c_int = 20;
+ pub const _SC_2_FORT_DEV: c_int = 21;
+ pub const _SC_2_FORT_RUN: c_int = 22;
+ pub const _SC_2_LOCALEDEF: c_int = 23;
+ pub const _SC_2_SW_DEV: c_int = 24;
+ pub const _SC_2_UPE: c_int = 25;
+ pub const _SC_STREAM_MAX: c_int = 26;
+ pub const _SC_TZNAME_MAX: c_int = 27;
+ pub const _SC_PAGESIZE: c_int = 28;
+ pub const _SC_FSYNC: c_int = 29;
+ pub const _SC_SEM_NSEMS_MAX: c_int = 31;
+ pub const _SC_SEM_VALUE_MAX: c_int = 32;
+ pub const _SC_AIO_LISTIO_MAX: c_int = 42;
+ pub const _SC_AIO_MAX: c_int = 43;
+ pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44;
+ pub const _SC_ASYNCHRONOUS_IO: c_int = 45;
+ pub const _SC_DELAYTIMER_MAX: c_int = 50;
+ pub const _SC_MAPPED_FILES: c_int = 53;
+ pub const _SC_MEMLOCK: c_int = 54;
+ pub const _SC_MEMLOCK_RANGE: c_int = 55;
+ pub const _SC_MEMORY_PROTECTION: c_int = 56;
+ pub const _SC_MESSAGE_PASSING: c_int = 57;
+ pub const _SC_MQ_OPEN_MAX: c_int = 58;
+ pub const _SC_PRIORITIZED_IO: c_int = 60;
+ pub const _SC_PRIORITY_SCHEDULING: c_int = 61;
+ pub const _SC_REALTIME_SIGNALS: c_int = 64;
+ pub const _SC_RTSIG_MAX: c_int = 66;
+ pub const _SC_SEMAPHORES: c_int = 67;
+ pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 68;
+ pub const _SC_SIGQUEUE_MAX: c_int = 70;
+ pub const _SC_SYNCHRONIZED_IO: c_int = 75;
+ pub const _SC_TIMER_MAX: c_int = 93;
+ pub const _SC_TIMERS: c_int = 94;
+
+ pub const _PC_NAME_MAX: c_int = 4;
+ pub const _PC_PATH_MAX: c_int = 5;
+ }
+ }
+
+ #[cfg(target_os = "netbsd")]
+ pub mod os {
+ pub mod c95 {
+ use types::os::arch::c95::{c_int, c_uint};
+
+ pub const EXIT_FAILURE: c_int = 1;
+ pub const EXIT_SUCCESS: c_int = 0;
+ pub const RAND_MAX: c_int = 2147483647;
+ pub const EOF: c_int = -1;
+ pub const SEEK_SET: c_int = 0;
+ pub const SEEK_CUR: c_int = 1;
+ pub const SEEK_END: c_int = 2;
+ pub const _IOFBF: c_int = 0;
+ pub const _IONBF: c_int = 2;
+ pub const _IOLBF: c_int = 1;
+ pub const BUFSIZ: c_uint = 1024;
+ pub const FOPEN_MAX: c_uint = 20;
+ pub const FILENAME_MAX: c_uint = 1024;
+ pub const L_tmpnam: c_uint = 1024;
+ pub const TMP_MAX: c_uint = 308915776;
+ }
+ pub mod c99 {
+ }
+ pub mod posix88 {
+ use types::common::c95::c_void;
+ use types::os::arch::c95::c_int;
+ use types::os::arch::posix88::mode_t;
+
+ pub const O_RDONLY: c_int = 0;
+ pub const O_WRONLY: c_int = 1;
+ pub const O_RDWR: c_int = 2;
+ pub const O_APPEND: c_int = 8;
+ pub const O_CREAT: c_int = 512;
+ pub const O_EXCL: c_int = 2048;
+ pub const O_NOCTTY: c_int = 32768;
+ pub const O_TRUNC: c_int = 1024;
+ pub const S_IFIFO: mode_t = 4096;
+ pub const S_IFCHR: mode_t = 8192;
+ pub const S_IFBLK: mode_t = 24576;
+ pub const S_IFDIR: mode_t = 16384;
+ pub const S_IFREG: mode_t = 32768;
+ pub const S_IFLNK: mode_t = 40960;
+ pub const S_IFSOCK: mode_t = 49152;
+ pub const S_IFMT: mode_t = 61440;
+ pub const S_IEXEC: mode_t = 64;
+ pub const S_IWRITE: mode_t = 128;
+ pub const S_IREAD: mode_t = 256;
+ pub const S_IRWXU: mode_t = 448;
+ pub const S_IXUSR: mode_t = 64;
+ pub const S_IWUSR: mode_t = 128;
+ pub const S_IRUSR: mode_t = 256;
+ pub const S_IRWXG: mode_t = 56;
+ pub const S_IXGRP: mode_t = 8;
+ pub const S_IWGRP: mode_t = 16;
+ pub const S_IRGRP: mode_t = 32;
+ pub const S_IRWXO: mode_t = 7;
+ pub const S_IXOTH: mode_t = 1;
+ pub const S_IWOTH: mode_t = 2;
+ pub const S_IROTH: mode_t = 4;
+ pub const F_OK: c_int = 0;
+ pub const R_OK: c_int = 4;
+ pub const W_OK: c_int = 2;
+ pub const X_OK: c_int = 1;
+ pub const STDIN_FILENO: c_int = 0;
+ pub const STDOUT_FILENO: c_int = 1;
+ pub const STDERR_FILENO: c_int = 2;
+ pub const F_LOCK: c_int = 1;
+ pub const F_TEST: c_int = 3;
+ pub const F_TLOCK: c_int = 2;
+ pub const F_ULOCK: c_int = 0;
+ pub const SIGHUP: c_int = 1;
+ pub const SIGINT: c_int = 2;
+ pub const SIGQUIT: c_int = 3;
+ pub const SIGILL: c_int = 4;
+ pub const SIGABRT: c_int = 6;
+ pub const SIGFPE: c_int = 8;
+ pub const SIGKILL: c_int = 9;
+ pub const SIGSEGV: c_int = 11;
+ pub const SIGPIPE: c_int = 13;
+ pub const SIGALRM: c_int = 14;
+ pub const SIGTERM: c_int = 15;
+
+ pub const PROT_NONE: c_int = 0;
+ pub const PROT_READ: c_int = 1;
+ pub const PROT_WRITE: c_int = 2;
+ pub const PROT_EXEC: c_int = 4;
+
+ pub const MAP_FILE: c_int = 0;
+ pub const MAP_SHARED: c_int = 1;
+ pub const MAP_PRIVATE: c_int = 2;
+ pub const MAP_FIXED: c_int = 16;
+ pub const MAP_ANON: c_int = 4096;
+
+ pub const MAP_FAILED: *mut c_void = !0 as *mut c_void;
+
+ pub const MCL_CURRENT: c_int = 1;
+ pub const MCL_FUTURE: c_int = 2;
+
+ pub const MS_ASYNC: c_int = 1;
+ pub const MS_SYNC: c_int = 4;
+ pub const MS_INVALIDATE: c_int = 2;
+
+ pub const EPERM: c_int = 1;
+ pub const ENOENT: c_int = 2;
+ pub const ESRCH: c_int = 3;
+ pub const EINTR: c_int = 4;
+ pub const EIO: c_int = 5;
+ pub const ENXIO: c_int = 6;
+ pub const E2BIG: c_int = 7;
+ pub const ENOEXEC: c_int = 8;
+ pub const EBADF: c_int = 9;
+ pub const ECHILD: c_int = 10;
+ pub const EDEADLK: c_int = 11;
+ pub const ENOMEM: c_int = 12;
+ pub const EACCES: c_int = 13;
+ pub const EFAULT: c_int = 14;
+ pub const ENOTBLK: c_int = 15;
+ pub const EBUSY: c_int = 16;
+ pub const EEXIST: c_int = 17;
+ pub const EXDEV: c_int = 18;
+ pub const ENODEV: c_int = 19;
+ pub const ENOTDIR: c_int = 20;
+ pub const EISDIR: c_int = 21;
+ pub const EINVAL: c_int = 22;
+ pub const ENFILE: c_int = 23;
+ pub const EMFILE: c_int = 24;
+ pub const ENOTTY: c_int = 25;
+ pub const ETXTBSY: c_int = 26;
+ pub const EFBIG: c_int = 27;
+ pub const ENOSPC: c_int = 28;
+ pub const ESPIPE: c_int = 29;
+ pub const EROFS: c_int = 30;
+ pub const EMLINK: c_int = 31;
+ pub const EPIPE: c_int = 32;
+ pub const EDOM: c_int = 33;
+ pub const ERANGE: c_int = 34;
+ pub const EAGAIN: c_int = 35;
+ pub const EWOULDBLOCK: c_int = 35;
+ pub const EINPROGRESS: c_int = 36;
+ pub const EALREADY: c_int = 37;
+ pub const ENOTSOCK: c_int = 38;
+ pub const EDESTADDRREQ: c_int = 39;
+ pub const EMSGSIZE: c_int = 40;
+ pub const EPROTOTYPE: c_int = 41;
+ pub const ENOPROTOOPT: c_int = 42;
+ pub const EPROTONOSUPPORT: c_int = 43;
+ pub const ESOCKTNOSUPPORT: c_int = 44;
+ pub const EOPNOTSUPP: c_int = 45;
+ pub const EPFNOSUPPORT: c_int = 46;
+ pub const EAFNOSUPPORT: c_int = 47;
+ pub const EADDRINUSE: c_int = 48;
+ pub const EADDRNOTAVAIL: c_int = 49;
+ pub const ENETDOWN: c_int = 50;
+ pub const ENETUNREACH: c_int = 51;
+ pub const ENETRESET: c_int = 52;
+ pub const ECONNABORTED: c_int = 53;
+ pub const ECONNRESET: c_int = 54;
+ pub const ENOBUFS: c_int = 55;
+ pub const EISCONN: c_int = 56;
+ pub const ENOTCONN: c_int = 57;
+ pub const ESHUTDOWN: c_int = 58;
+ pub const ETOOMANYREFS: c_int = 59;
+ pub const ETIMEDOUT: c_int = 60;
+ pub const ECONNREFUSED: c_int = 61;
+ pub const ELOOP: c_int = 62;
+ pub const ENAMETOOLONG: c_int = 63;
+ pub const EHOSTDOWN: c_int = 64;
+ pub const EHOSTUNREACH: c_int = 65;
+ pub const ENOTEMPTY: c_int = 66;
+ pub const EPROCLIM: c_int = 67;
+ pub const EUSERS: c_int = 68;
+ pub const EDQUOT: c_int = 69;
+ pub const ESTALE: c_int = 70;
+ pub const EREMOTE: c_int = 71;
+ pub const EBADRPC: c_int = 72;
+ pub const ERPCMISMATCH: c_int = 73;
+ pub const EPROGUNAVAIL: c_int = 74;
+ pub const EPROGMISMATCH: c_int = 75;
+ pub const EPROCUNAVAIL: c_int = 76;
+ pub const ENOLCK: c_int = 77;
+ pub const ENOSYS: c_int = 78;
+ pub const EFTYPE: c_int = 79;
+ pub const EAUTH: c_int = 80;
+ pub const ENEEDAUTH: c_int = 81;
+ pub const ENOATTR: c_int = 93;
+ pub const EILSEQ: c_int = 85;
+ pub const EOVERFLOW: c_int = 84;
+ pub const ECANCELED: c_int = 87;
+ pub const EIDRM: c_int = 82;
+ pub const ENOMSG: c_int = 83;
+ pub const ENOTSUP: c_int = 86;
+ pub const ELAST: c_int = 96;
+ }
+ pub mod posix01 {
+ use types::os::arch::c95::{c_int, size_t};
+ use types::os::common::posix01::rlim_t;
+
+ pub const F_DUPFD: c_int = 0;
+ pub const F_GETFD: c_int = 1;
+ pub const F_SETFD: c_int = 2;
+ pub const F_GETFL: c_int = 3;
+ pub const F_SETFL: c_int = 4;
+ pub const F_GETOWN: c_int = 5;
+ pub const F_SETOWN: c_int = 6;
+ pub const F_GETLK: c_int = 7;
+ pub const F_SETLK: c_int = 8;
+ pub const F_SETLKW: c_int = 9;
+
+ pub const SIGTRAP: c_int = 5;
+ pub const SIG_IGN: size_t = 1;
+
+ pub const GLOB_APPEND: c_int = 1;
+ pub const GLOB_DOOFFS: c_int = 2;
+ pub const GLOB_ERR: c_int = 4;
+ pub const GLOB_MARK: c_int = 8;
+ pub const GLOB_NOCHECK: c_int = 16;
+ pub const GLOB_NOSORT: c_int = 32;
+ pub const GLOB_NOESCAPE: c_int = 4096;
+
+ pub const GLOB_NOSPACE: c_int = -1;
+ pub const GLOB_ABORTED: c_int = -2;
+ pub const GLOB_NOMATCH: c_int = -3;
+ pub const GLOB_NOSYS: c_int = -4;
+
+ pub const POSIX_MADV_NORMAL: c_int = 0;
+ pub const POSIX_MADV_RANDOM: c_int = 1;
+ pub const POSIX_MADV_SEQUENTIAL: c_int = 2;
+ pub const POSIX_MADV_WILLNEED: c_int = 3;
+ pub const POSIX_MADV_DONTNEED: c_int = 4;
+
+ pub const _SC_IOV_MAX: c_int = 32;
+ pub const _SC_GETGR_R_SIZE_MAX: c_int = 47;
+ pub const _SC_GETPW_R_SIZE_MAX: c_int = 48;
+ pub const _SC_LOGIN_NAME_MAX: c_int = 37;
+ pub const _SC_MQ_PRIO_MAX: c_int = 55;
+ pub const _SC_THREAD_ATTR_STACKADDR: c_int = 61;
+ pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 62;
+ pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 57;
+ pub const _SC_THREAD_KEYS_MAX: c_int = 58;
+ pub const _SC_THREAD_PRIO_INHERIT: c_int = 64;
+ pub const _SC_THREAD_PRIO_PROTECT: c_int = 65;
+ pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 63;
+ pub const _SC_THREAD_PROCESS_SHARED: c_int = 66;
+ pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 67;
+ pub const _SC_THREAD_STACK_MIN: c_int = 59;
+ pub const _SC_THREAD_THREADS_MAX: c_int = 60;
+ pub const _SC_THREADS: c_int = 41;
+ pub const _SC_TTY_NAME_MAX: c_int = 68;
+ pub const _SC_ATEXIT_MAX: c_int = 40;
+ pub const _SC_XOPEN_SHM: c_int = 30;
+
+ pub const PTHREAD_CREATE_JOINABLE: c_int = 0;
+ pub const PTHREAD_CREATE_DETACHED: c_int = 1;
+ pub const PTHREAD_STACK_MIN: size_t = 2048;
+
+ pub const CLOCK_REALTIME: c_int = 0;
+ pub const CLOCK_MONOTONIC: c_int = 3;
+
+ pub const RLIMIT_CPU: c_int = 0;
+ pub const RLIMIT_FSIZE: c_int = 1;
+ pub const RLIMIT_DATA: c_int = 2;
+ pub const RLIMIT_STACK: c_int = 3;
+ pub const RLIMIT_CORE: c_int = 4;
+ pub const RLIMIT_RSS: c_int = 5;
+ pub const RLIMIT_MEMLOCK: c_int = 6;
+ pub const RLIMIT_NPROC: c_int = 7;
+ pub const RLIMIT_NOFILE: c_int = 8;
+ pub const RLIM_NLIMITS: c_int = 9;
+
+ pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff;
+ pub const RLIM_SAVED_MAX: rlim_t = RLIM_INFINITY;
+ pub const RLIM_SAVED_CUR: rlim_t = RLIM_INFINITY;
+
+ pub const RUSAGE_SELF: c_int = 0;
+ pub const RUSAGE_CHILDREN: c_int = -1;
+ pub const RUSAGE_THREAD: c_int = 1;
+ }
+ pub mod posix08 {
+ use types::os::arch::c95::c_int;
+ pub const O_CLOEXEC: c_int = 0x400000;
+ pub const F_DUPFD_CLOEXEC: c_int = 12;
+ }
+ pub mod bsd44 {
+ use types::os::arch::c95::c_int;
+
+ pub const MADV_NORMAL: c_int = 0;
+ pub const MADV_RANDOM: c_int = 1;
+ pub const MADV_SEQUENTIAL: c_int = 2;
+ pub const MADV_WILLNEED: c_int = 3;
+ pub const MADV_DONTNEED: c_int = 4;
+ pub const MADV_FREE: c_int = 6;
+
+ pub const AF_UNIX: c_int = 1;
+ pub const AF_INET: c_int = 2;
+ pub const AF_INET6: c_int = 24;
+ pub const SOCK_STREAM: c_int = 1;
+ pub const SOCK_DGRAM: c_int = 2;
+ pub const SOCK_RAW: c_int = 3;
+ pub const IPPROTO_TCP: c_int = 6;
+ pub const IPPROTO_IP: c_int = 0;
+ pub const IPPROTO_IPV6: c_int = 41;
+ pub const IP_MULTICAST_TTL: c_int = 10;
+ pub const IP_MULTICAST_LOOP: c_int = 11;
+ pub const IP_TTL: c_int = 4;
+ pub const IP_HDRINCL: c_int = 2;
+ pub const IP_ADD_MEMBERSHIP: c_int = 12;
+ pub const IP_DROP_MEMBERSHIP: c_int = 13;
+
+ pub const TCP_NODELAY: c_int = 1;
+ pub const SOL_SOCKET: c_int = 65535;
+ pub const SO_DEBUG: c_int = 1;
+ pub const SO_ACCEPTCONN: c_int = 2;
+ pub const SO_REUSEADDR: c_int = 4;
+ pub const SO_KEEPALIVE: c_int = 8;
+ pub const SO_DONTROUTE: c_int = 16;
+ pub const SO_BROADCAST: c_int = 32;
+ pub const SO_USELOOPBACK: c_int = 64;
+ pub const SO_LINGER: c_int = 128;
+ pub const SO_OOBINLINE: c_int = 256;
+ pub const SO_REUSEPORT: c_int = 512;
+ pub const SO_SNDBUF: c_int = 4097;
+ pub const SO_RCVBUF: c_int = 4098;
+ pub const SO_SNDLOWAT: c_int = 4099;
+ pub const SO_RCVLOWAT: c_int = 4100;
+ pub const SO_SNDTIMEO: c_int = 4107;
+ pub const SO_RCVTIMEO: c_int = 4108;
+ pub const SO_ERROR: c_int = 4103;
+ pub const SO_TYPE: c_int = 4104;
+
+ pub const IFF_LOOPBACK: c_int = 0x8;
+
+ pub const SHUT_RD: c_int = 0;
+ pub const SHUT_WR: c_int = 1;
+ pub const SHUT_RDWR: c_int = 2;
+
+ pub const LOCK_SH: c_int = 1;
+ pub const LOCK_EX: c_int = 2;
+ pub const LOCK_NB: c_int = 4;
+ pub const LOCK_UN: c_int = 8;
+ }
+ pub mod extra {
+ use types::os::arch::c95::c_int;
+
+
+ pub const MAP_RENAME: c_int = 32;
+ pub const MAP_NORESERVE: c_int = 64;
+ pub const MAP_HASSEMAPHORE: c_int = 512;
+
+ pub const IPPROTO_RAW: c_int = 255;
+
+ pub const PATH_MAX: c_int = 1024;
+ }
+ pub mod sysconf {
+ use types::os::arch::c95::c_int;
+
+ pub const _SC_ARG_MAX: c_int = 1;
+ pub const _SC_CHILD_MAX: c_int = 2;
+ pub const _SC_CLK_TCK: c_int = 39;
+ pub const _SC_NGROUPS_MAX: c_int = 4;
+ pub const _SC_OPEN_MAX: c_int = 5;
+ pub const _SC_JOB_CONTROL: c_int = 6;
+ pub const _SC_SAVED_IDS: c_int = 7;
+ pub const _SC_VERSION: c_int = 8;
+ pub const _SC_BC_BASE_MAX: c_int = 9;
+ pub const _SC_BC_DIM_MAX: c_int = 10;
+ pub const _SC_BC_SCALE_MAX: c_int = 11;
+ pub const _SC_BC_STRING_MAX: c_int = 12;
+ pub const _SC_COLL_WEIGHTS_MAX: c_int = 13;
+ pub const _SC_EXPR_NEST_MAX: c_int = 14;
+ pub const _SC_LINE_MAX: c_int = 15;
+ pub const _SC_RE_DUP_MAX: c_int = 16;
+ pub const _SC_2_VERSION: c_int = 17;
+ pub const _SC_2_C_BIND: c_int = 18;
+ pub const _SC_2_C_DEV: c_int = 19;
+ pub const _SC_2_CHAR_TERM: c_int = 20;
+ pub const _SC_2_FORT_DEV: c_int = 21;
+ pub const _SC_2_FORT_RUN: c_int = 22;
+ pub const _SC_2_LOCALEDEF: c_int = 23;
+ pub const _SC_2_SW_DEV: c_int = 24;
+ pub const _SC_2_UPE: c_int = 25;
+ pub const _SC_STREAM_MAX: c_int = 26;
+ pub const _SC_TZNAME_MAX: c_int = 27;
+ pub const _SC_PAGESIZE: c_int = 28;
+ pub const _SC_FSYNC: c_int = 29;
+ pub const _SC_AIO_LISTIO_MAX: c_int = 51;
+ pub const _SC_AIO_MAX: c_int = 52;
+ pub const _SC_ASYNCHRONOUS_IO: c_int = 50;
+ pub const _SC_MAPPED_FILES: c_int = 33;
+ pub const _SC_MEMLOCK: c_int = 34;
+ pub const _SC_MEMLOCK_RANGE: c_int = 35;
+ pub const _SC_MEMORY_PROTECTION: c_int = 36;
+ pub const _SC_MESSAGE_PASSING: c_int = 53;
+ pub const _SC_MQ_OPEN_MAX: c_int = 54;
+ pub const _SC_PRIORITY_SCHEDULING: c_int = 56;
+ pub const _SC_SEMAPHORES: c_int = 42;
+ pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 87;
+ pub const _SC_SYNCHRONIZED_IO: c_int = 31;
+ pub const _SC_TIMERS: c_int = 44;
pub const _PC_NAME_MAX: c_int = 4;
pub const _PC_PATH_MAX: c_int = 5;
pub mod c95 {
use types::os::arch::c95::{c_int, c_uint};
- pub const EXIT_FAILURE : c_int = 1;
- pub const EXIT_SUCCESS : c_int = 0;
- pub const RAND_MAX : c_int = 2147483647;
- pub const EOF : c_int = -1;
- pub const SEEK_SET : c_int = 0;
- pub const SEEK_CUR : c_int = 1;
- pub const SEEK_END : c_int = 2;
- pub const _IOFBF : c_int = 0;
- pub const _IONBF : c_int = 2;
- pub const _IOLBF : c_int = 1;
- pub const BUFSIZ : c_uint = 1024;
- pub const FOPEN_MAX : c_uint = 20;
- pub const FILENAME_MAX : c_uint = 1024;
- pub const L_tmpnam : c_uint = 1024;
- pub const TMP_MAX : c_uint = 308915776;
+ pub const EXIT_FAILURE: c_int = 1;
+ pub const EXIT_SUCCESS: c_int = 0;
+ pub const RAND_MAX: c_int = 2147483647;
+ pub const EOF: c_int = -1;
+ pub const SEEK_SET: c_int = 0;
+ pub const SEEK_CUR: c_int = 1;
+ pub const SEEK_END: c_int = 2;
+ pub const _IOFBF: c_int = 0;
+ pub const _IONBF: c_int = 2;
+ pub const _IOLBF: c_int = 1;
+ pub const BUFSIZ: c_uint = 1024;
+ pub const FOPEN_MAX: c_uint = 20;
+ pub const FILENAME_MAX: c_uint = 1024;
+ pub const L_tmpnam: c_uint = 1024;
+ pub const TMP_MAX: c_uint = 308915776;
}
pub mod c99 {
}
use types::os::arch::c95::c_int;
use types::os::arch::posix88::mode_t;
- pub const O_RDONLY : c_int = 0;
- pub const O_WRONLY : c_int = 1;
- pub const O_RDWR : c_int = 2;
- pub const O_APPEND : c_int = 8;
- pub const O_CREAT : c_int = 512;
- pub const O_EXCL : c_int = 2048;
- pub const O_NOCTTY : c_int = 131072;
- pub const O_TRUNC : c_int = 1024;
- pub const S_IFIFO : mode_t = 4096;
- pub const S_IFCHR : mode_t = 8192;
- pub const S_IFBLK : mode_t = 24576;
- pub const S_IFDIR : mode_t = 16384;
- pub const S_IFREG : mode_t = 32768;
- pub const S_IFLNK : mode_t = 40960;
- pub const S_IFSOCK : mode_t = 49152;
- pub const S_IFMT : mode_t = 61440;
- pub const S_IEXEC : mode_t = 64;
- pub const S_IWRITE : mode_t = 128;
- pub const S_IREAD : mode_t = 256;
- pub const S_IRWXU : mode_t = 448;
- pub const S_IXUSR : mode_t = 64;
- pub const S_IWUSR : mode_t = 128;
- pub const S_IRUSR : mode_t = 256;
- pub const S_IRWXG : mode_t = 56;
- pub const S_IXGRP : mode_t = 8;
- pub const S_IWGRP : mode_t = 16;
- pub const S_IRGRP : mode_t = 32;
- pub const S_IRWXO : mode_t = 7;
- pub const S_IXOTH : mode_t = 1;
- pub const S_IWOTH : mode_t = 2;
- pub const S_IROTH : mode_t = 4;
- pub const F_OK : c_int = 0;
- pub const R_OK : c_int = 4;
- pub const W_OK : c_int = 2;
- pub const X_OK : c_int = 1;
- pub const STDIN_FILENO : c_int = 0;
- pub const STDOUT_FILENO : c_int = 1;
- pub const STDERR_FILENO : c_int = 2;
- pub const F_LOCK : c_int = 1;
- pub const F_TEST : c_int = 3;
- pub const F_TLOCK : c_int = 2;
- pub const F_ULOCK : c_int = 0;
- pub const SIGHUP : c_int = 1;
- pub const SIGINT : c_int = 2;
- pub const SIGQUIT : c_int = 3;
- pub const SIGILL : c_int = 4;
- pub const SIGABRT : c_int = 6;
- pub const SIGFPE : c_int = 8;
- pub const SIGKILL : c_int = 9;
- pub const SIGSEGV : c_int = 11;
- pub const SIGPIPE : c_int = 13;
- pub const SIGALRM : c_int = 14;
- pub const SIGTERM : c_int = 15;
-
- pub const PROT_NONE : c_int = 0;
- pub const PROT_READ : c_int = 1;
- pub const PROT_WRITE : c_int = 2;
- pub const PROT_EXEC : c_int = 4;
-
- pub const MAP_FILE : c_int = 0x0000;
- pub const MAP_SHARED : c_int = 0x0001;
- pub const MAP_PRIVATE : c_int = 0x0002;
- pub const MAP_FIXED : c_int = 0x0010;
- pub const MAP_ANON : c_int = 0x1000;
-
- pub const MAP_FAILED : *mut c_void = !0 as *mut c_void;
-
- pub const MCL_CURRENT : c_int = 0x0001;
- pub const MCL_FUTURE : c_int = 0x0002;
-
- pub const MS_ASYNC : c_int = 0x0001;
- pub const MS_INVALIDATE : c_int = 0x0002;
- pub const MS_SYNC : c_int = 0x0010;
-
- pub const MS_KILLPAGES : c_int = 0x0004;
- pub const MS_DEACTIVATE : c_int = 0x0008;
-
- pub const EPERM : c_int = 1;
- pub const ENOENT : c_int = 2;
- pub const ESRCH : c_int = 3;
- pub const EINTR : c_int = 4;
- pub const EIO : c_int = 5;
- pub const ENXIO : c_int = 6;
- pub const E2BIG : c_int = 7;
- pub const ENOEXEC : c_int = 8;
- pub const EBADF : c_int = 9;
- pub const ECHILD : c_int = 10;
- pub const EDEADLK : c_int = 11;
- pub const ENOMEM : c_int = 12;
- pub const EACCES : c_int = 13;
- pub const EFAULT : c_int = 14;
- pub const ENOTBLK : c_int = 15;
- pub const EBUSY : c_int = 16;
- pub const EEXIST : c_int = 17;
- pub const EXDEV : c_int = 18;
- pub const ENODEV : c_int = 19;
- pub const ENOTDIR : c_int = 20;
- pub const EISDIR : c_int = 21;
- pub const EINVAL : c_int = 22;
- pub const ENFILE : c_int = 23;
- pub const EMFILE : c_int = 24;
- pub const ENOTTY : c_int = 25;
- pub const ETXTBSY : c_int = 26;
- pub const EFBIG : c_int = 27;
- pub const ENOSPC : c_int = 28;
- pub const ESPIPE : c_int = 29;
- pub const EROFS : c_int = 30;
- pub const EMLINK : c_int = 31;
- pub const EPIPE : c_int = 32;
- pub const EDOM : c_int = 33;
- pub const ERANGE : c_int = 34;
- pub const EAGAIN : c_int = 35;
- pub const EWOULDBLOCK : c_int = EAGAIN;
- pub const EINPROGRESS : c_int = 36;
- pub const EALREADY : c_int = 37;
- pub const ENOTSOCK : c_int = 38;
- pub const EDESTADDRREQ : c_int = 39;
- pub const EMSGSIZE : c_int = 40;
- pub const EPROTOTYPE : c_int = 41;
- pub const ENOPROTOOPT : c_int = 42;
- pub const EPROTONOSUPPORT : c_int = 43;
- pub const ESOCKTNOSUPPORT : c_int = 44;
- pub const ENOTSUP : c_int = 45;
- pub const EPFNOSUPPORT : c_int = 46;
- pub const EAFNOSUPPORT : c_int = 47;
- pub const EADDRINUSE : c_int = 48;
- pub const EADDRNOTAVAIL : c_int = 49;
- pub const ENETDOWN : c_int = 50;
- pub const ENETUNREACH : c_int = 51;
- pub const ENETRESET : c_int = 52;
- pub const ECONNABORTED : c_int = 53;
- pub const ECONNRESET : c_int = 54;
- pub const ENOBUFS : c_int = 55;
- pub const EISCONN : c_int = 56;
- pub const ENOTCONN : c_int = 57;
- pub const ESHUTDOWN : c_int = 58;
- pub const ETOOMANYREFS : c_int = 59;
- pub const ETIMEDOUT : c_int = 60;
- pub const ECONNREFUSED : c_int = 61;
- pub const ELOOP : c_int = 62;
- pub const ENAMETOOLONG : c_int = 63;
- pub const EHOSTDOWN : c_int = 64;
- pub const EHOSTUNREACH : c_int = 65;
- pub const ENOTEMPTY : c_int = 66;
- pub const EPROCLIM : c_int = 67;
- pub const EUSERS : c_int = 68;
- pub const EDQUOT : c_int = 69;
- pub const ESTALE : c_int = 70;
- pub const EREMOTE : c_int = 71;
- pub const EBADRPC : c_int = 72;
- pub const ERPCMISMATCH : c_int = 73;
- pub const EPROGUNAVAIL : c_int = 74;
- pub const EPROGMISMATCH : c_int = 75;
- pub const EPROCUNAVAIL : c_int = 76;
- pub const ENOLCK : c_int = 77;
- pub const ENOSYS : c_int = 78;
- pub const EFTYPE : c_int = 79;
- pub const EAUTH : c_int = 80;
- pub const ENEEDAUTH : c_int = 81;
- pub const EPWROFF : c_int = 82;
- pub const EDEVERR : c_int = 83;
- pub const EOVERFLOW : c_int = 84;
- pub const EBADEXEC : c_int = 85;
- pub const EBADARCH : c_int = 86;
- pub const ESHLIBVERS : c_int = 87;
- pub const EBADMACHO : c_int = 88;
- pub const ECANCELED : c_int = 89;
- pub const EIDRM : c_int = 90;
- pub const ENOMSG : c_int = 91;
- pub const EILSEQ : c_int = 92;
- pub const ENOATTR : c_int = 93;
- pub const EBADMSG : c_int = 94;
- pub const EMULTIHOP : c_int = 95;
- pub const ENODATA : c_int = 96;
- pub const ENOLINK : c_int = 97;
- pub const ENOSR : c_int = 98;
- pub const ENOSTR : c_int = 99;
- pub const EPROTO : c_int = 100;
- pub const ETIME : c_int = 101;
- pub const EOPNOTSUPP : c_int = 102;
- pub const ENOPOLICY : c_int = 103;
- pub const ENOTRECOVERABLE : c_int = 104;
- pub const EOWNERDEAD : c_int = 105;
- pub const EQFULL : c_int = 106;
- pub const ELAST : c_int = 106;
+ pub const O_RDONLY: c_int = 0;
+ pub const O_WRONLY: c_int = 1;
+ pub const O_RDWR: c_int = 2;
+ pub const O_APPEND: c_int = 8;
+ pub const O_CREAT: c_int = 512;
+ pub const O_EXCL: c_int = 2048;
+ pub const O_NOCTTY: c_int = 131072;
+ pub const O_TRUNC: c_int = 1024;
+ pub const S_IFIFO: mode_t = 4096;
+ pub const S_IFCHR: mode_t = 8192;
+ pub const S_IFBLK: mode_t = 24576;
+ pub const S_IFDIR: mode_t = 16384;
+ pub const S_IFREG: mode_t = 32768;
+ pub const S_IFLNK: mode_t = 40960;
+ pub const S_IFSOCK: mode_t = 49152;
+ pub const S_IFMT: mode_t = 61440;
+ pub const S_IEXEC: mode_t = 64;
+ pub const S_IWRITE: mode_t = 128;
+ pub const S_IREAD: mode_t = 256;
+ pub const S_IRWXU: mode_t = 448;
+ pub const S_IXUSR: mode_t = 64;
+ pub const S_IWUSR: mode_t = 128;
+ pub const S_IRUSR: mode_t = 256;
+ pub const S_IRWXG: mode_t = 56;
+ pub const S_IXGRP: mode_t = 8;
+ pub const S_IWGRP: mode_t = 16;
+ pub const S_IRGRP: mode_t = 32;
+ pub const S_IRWXO: mode_t = 7;
+ pub const S_IXOTH: mode_t = 1;
+ pub const S_IWOTH: mode_t = 2;
+ pub const S_IROTH: mode_t = 4;
+ pub const F_OK: c_int = 0;
+ pub const R_OK: c_int = 4;
+ pub const W_OK: c_int = 2;
+ pub const X_OK: c_int = 1;
+ pub const STDIN_FILENO: c_int = 0;
+ pub const STDOUT_FILENO: c_int = 1;
+ pub const STDERR_FILENO: c_int = 2;
+ pub const F_LOCK: c_int = 1;
+ pub const F_TEST: c_int = 3;
+ pub const F_TLOCK: c_int = 2;
+ pub const F_ULOCK: c_int = 0;
+ pub const SIGHUP: c_int = 1;
+ pub const SIGINT: c_int = 2;
+ pub const SIGQUIT: c_int = 3;
+ pub const SIGILL: c_int = 4;
+ pub const SIGABRT: c_int = 6;
+ pub const SIGFPE: c_int = 8;
+ pub const SIGKILL: c_int = 9;
+ pub const SIGSEGV: c_int = 11;
+ pub const SIGPIPE: c_int = 13;
+ pub const SIGALRM: c_int = 14;
+ pub const SIGTERM: c_int = 15;
+
+ pub const PROT_NONE: c_int = 0;
+ pub const PROT_READ: c_int = 1;
+ pub const PROT_WRITE: c_int = 2;
+ pub const PROT_EXEC: c_int = 4;
+
+ pub const MAP_FILE: c_int = 0x0000;
+ pub const MAP_SHARED: c_int = 0x0001;
+ pub const MAP_PRIVATE: c_int = 0x0002;
+ pub const MAP_FIXED: c_int = 0x0010;
+ pub const MAP_ANON: c_int = 0x1000;
+
+ pub const MAP_FAILED: *mut c_void = !0 as *mut c_void;
+
+ pub const MCL_CURRENT: c_int = 0x0001;
+ pub const MCL_FUTURE: c_int = 0x0002;
+
+ pub const MS_ASYNC: c_int = 0x0001;
+ pub const MS_INVALIDATE: c_int = 0x0002;
+ pub const MS_SYNC: c_int = 0x0010;
+
+ pub const MS_KILLPAGES: c_int = 0x0004;
+ pub const MS_DEACTIVATE: c_int = 0x0008;
+
+ pub const EPERM: c_int = 1;
+ pub const ENOENT: c_int = 2;
+ pub const ESRCH: c_int = 3;
+ pub const EINTR: c_int = 4;
+ pub const EIO: c_int = 5;
+ pub const ENXIO: c_int = 6;
+ pub const E2BIG: c_int = 7;
+ pub const ENOEXEC: c_int = 8;
+ pub const EBADF: c_int = 9;
+ pub const ECHILD: c_int = 10;
+ pub const EDEADLK: c_int = 11;
+ pub const ENOMEM: c_int = 12;
+ pub const EACCES: c_int = 13;
+ pub const EFAULT: c_int = 14;
+ pub const ENOTBLK: c_int = 15;
+ pub const EBUSY: c_int = 16;
+ pub const EEXIST: c_int = 17;
+ pub const EXDEV: c_int = 18;
+ pub const ENODEV: c_int = 19;
+ pub const ENOTDIR: c_int = 20;
+ pub const EISDIR: c_int = 21;
+ pub const EINVAL: c_int = 22;
+ pub const ENFILE: c_int = 23;
+ pub const EMFILE: c_int = 24;
+ pub const ENOTTY: c_int = 25;
+ pub const ETXTBSY: c_int = 26;
+ pub const EFBIG: c_int = 27;
+ pub const ENOSPC: c_int = 28;
+ pub const ESPIPE: c_int = 29;
+ pub const EROFS: c_int = 30;
+ pub const EMLINK: c_int = 31;
+ pub const EPIPE: c_int = 32;
+ pub const EDOM: c_int = 33;
+ pub const ERANGE: c_int = 34;
+ pub const EAGAIN: c_int = 35;
+ pub const EWOULDBLOCK: c_int = EAGAIN;
+ pub const EINPROGRESS: c_int = 36;
+ pub const EALREADY: c_int = 37;
+ pub const ENOTSOCK: c_int = 38;
+ pub const EDESTADDRREQ: c_int = 39;
+ pub const EMSGSIZE: c_int = 40;
+ pub const EPROTOTYPE: c_int = 41;
+ pub const ENOPROTOOPT: c_int = 42;
+ pub const EPROTONOSUPPORT: c_int = 43;
+ pub const ESOCKTNOSUPPORT: c_int = 44;
+ pub const ENOTSUP: c_int = 45;
+ pub const EPFNOSUPPORT: c_int = 46;
+ pub const EAFNOSUPPORT: c_int = 47;
+ pub const EADDRINUSE: c_int = 48;
+ pub const EADDRNOTAVAIL: c_int = 49;
+ pub const ENETDOWN: c_int = 50;
+ pub const ENETUNREACH: c_int = 51;
+ pub const ENETRESET: c_int = 52;
+ pub const ECONNABORTED: c_int = 53;
+ pub const ECONNRESET: c_int = 54;
+ pub const ENOBUFS: c_int = 55;
+ pub const EISCONN: c_int = 56;
+ pub const ENOTCONN: c_int = 57;
+ pub const ESHUTDOWN: c_int = 58;
+ pub const ETOOMANYREFS: c_int = 59;
+ pub const ETIMEDOUT: c_int = 60;
+ pub const ECONNREFUSED: c_int = 61;
+ pub const ELOOP: c_int = 62;
+ pub const ENAMETOOLONG: c_int = 63;
+ pub const EHOSTDOWN: c_int = 64;
+ pub const EHOSTUNREACH: c_int = 65;
+ pub const ENOTEMPTY: c_int = 66;
+ pub const EPROCLIM: c_int = 67;
+ pub const EUSERS: c_int = 68;
+ pub const EDQUOT: c_int = 69;
+ pub const ESTALE: c_int = 70;
+ pub const EREMOTE: c_int = 71;
+ pub const EBADRPC: c_int = 72;
+ pub const ERPCMISMATCH: c_int = 73;
+ pub const EPROGUNAVAIL: c_int = 74;
+ pub const EPROGMISMATCH: c_int = 75;
+ pub const EPROCUNAVAIL: c_int = 76;
+ pub const ENOLCK: c_int = 77;
+ pub const ENOSYS: c_int = 78;
+ pub const EFTYPE: c_int = 79;
+ pub const EAUTH: c_int = 80;
+ pub const ENEEDAUTH: c_int = 81;
+ pub const EPWROFF: c_int = 82;
+ pub const EDEVERR: c_int = 83;
+ pub const EOVERFLOW: c_int = 84;
+ pub const EBADEXEC: c_int = 85;
+ pub const EBADARCH: c_int = 86;
+ pub const ESHLIBVERS: c_int = 87;
+ pub const EBADMACHO: c_int = 88;
+ pub const ECANCELED: c_int = 89;
+ pub const EIDRM: c_int = 90;
+ pub const ENOMSG: c_int = 91;
+ pub const EILSEQ: c_int = 92;
+ pub const ENOATTR: c_int = 93;
+ pub const EBADMSG: c_int = 94;
+ pub const EMULTIHOP: c_int = 95;
+ pub const ENODATA: c_int = 96;
+ pub const ENOLINK: c_int = 97;
+ pub const ENOSR: c_int = 98;
+ pub const ENOSTR: c_int = 99;
+ pub const EPROTO: c_int = 100;
+ pub const ETIME: c_int = 101;
+ pub const EOPNOTSUPP: c_int = 102;
+ pub const ENOPOLICY: c_int = 103;
+ pub const ENOTRECOVERABLE: c_int = 104;
+ pub const EOWNERDEAD: c_int = 105;
+ pub const EQFULL: c_int = 106;
+ pub const ELAST: c_int = 106;
}
pub mod posix01 {
use types::os::arch::c95::{c_int, size_t};
use types::os::common::posix01::rlim_t;
- pub const F_DUPFD : c_int = 0;
- pub const F_GETFD : c_int = 1;
- pub const F_SETFD : c_int = 2;
- pub const F_GETFL : c_int = 3;
- pub const F_SETFL : c_int = 4;
+ pub const F_DUPFD: c_int = 0;
+ pub const F_GETFD: c_int = 1;
+ pub const F_SETFD: c_int = 2;
+ pub const F_GETFL: c_int = 3;
+ pub const F_SETFL: c_int = 4;
- pub const O_ACCMODE : c_int = 3;
+ pub const O_ACCMODE: c_int = 3;
- pub const SIGTRAP : c_int = 5;
+ pub const SIGTRAP: c_int = 5;
pub const SIG_IGN: size_t = 1;
- pub const GLOB_APPEND : c_int = 0x0001;
- pub const GLOB_DOOFFS : c_int = 0x0002;
- pub const GLOB_ERR : c_int = 0x0004;
- pub const GLOB_MARK : c_int = 0x0008;
- pub const GLOB_NOCHECK : c_int = 0x0010;
- pub const GLOB_NOSORT : c_int = 0x0020;
- pub const GLOB_NOESCAPE : c_int = 0x2000;
-
- pub const GLOB_NOSPACE : c_int = -1;
- pub const GLOB_ABORTED : c_int = -2;
- pub const GLOB_NOMATCH : c_int = -3;
-
- pub const POSIX_MADV_NORMAL : c_int = 0;
- pub const POSIX_MADV_RANDOM : c_int = 1;
- pub const POSIX_MADV_SEQUENTIAL : c_int = 2;
- pub const POSIX_MADV_WILLNEED : c_int = 3;
- pub const POSIX_MADV_DONTNEED : c_int = 4;
-
- pub const _SC_IOV_MAX : c_int = 56;
- pub const _SC_GETGR_R_SIZE_MAX : c_int = 70;
- pub const _SC_GETPW_R_SIZE_MAX : c_int = 71;
- pub const _SC_LOGIN_NAME_MAX : c_int = 73;
- pub const _SC_MQ_PRIO_MAX : c_int = 75;
- pub const _SC_THREAD_ATTR_STACKADDR : c_int = 82;
- pub const _SC_THREAD_ATTR_STACKSIZE : c_int = 83;
- pub const _SC_THREAD_DESTRUCTOR_ITERATIONS : c_int = 85;
- pub const _SC_THREAD_KEYS_MAX : c_int = 86;
- pub const _SC_THREAD_PRIO_INHERIT : c_int = 87;
- pub const _SC_THREAD_PRIO_PROTECT : c_int = 88;
- pub const _SC_THREAD_PRIORITY_SCHEDULING : c_int = 89;
- pub const _SC_THREAD_PROCESS_SHARED : c_int = 90;
- pub const _SC_THREAD_SAFE_FUNCTIONS : c_int = 91;
- pub const _SC_THREAD_STACK_MIN : c_int = 93;
- pub const _SC_THREAD_THREADS_MAX : c_int = 94;
- pub const _SC_THREADS : c_int = 96;
- pub const _SC_TTY_NAME_MAX : c_int = 101;
- pub const _SC_ATEXIT_MAX : c_int = 107;
- pub const _SC_XOPEN_CRYPT : c_int = 108;
- pub const _SC_XOPEN_ENH_I18N : c_int = 109;
- pub const _SC_XOPEN_LEGACY : c_int = 110;
- pub const _SC_XOPEN_REALTIME : c_int = 111;
- pub const _SC_XOPEN_REALTIME_THREADS : c_int = 112;
- pub const _SC_XOPEN_SHM : c_int = 113;
- pub const _SC_XOPEN_UNIX : c_int = 115;
- pub const _SC_XOPEN_VERSION : c_int = 116;
- pub const _SC_XOPEN_XCU_VERSION : c_int = 121;
+ pub const GLOB_APPEND: c_int = 0x0001;
+ pub const GLOB_DOOFFS: c_int = 0x0002;
+ pub const GLOB_ERR: c_int = 0x0004;
+ pub const GLOB_MARK: c_int = 0x0008;
+ pub const GLOB_NOCHECK: c_int = 0x0010;
+ pub const GLOB_NOSORT: c_int = 0x0020;
+ pub const GLOB_NOESCAPE: c_int = 0x2000;
+
+ pub const GLOB_NOSPACE: c_int = -1;
+ pub const GLOB_ABORTED: c_int = -2;
+ pub const GLOB_NOMATCH: c_int = -3;
+
+ pub const POSIX_MADV_NORMAL: c_int = 0;
+ pub const POSIX_MADV_RANDOM: c_int = 1;
+ pub const POSIX_MADV_SEQUENTIAL: c_int = 2;
+ pub const POSIX_MADV_WILLNEED: c_int = 3;
+ pub const POSIX_MADV_DONTNEED: c_int = 4;
+
+ pub const _SC_IOV_MAX: c_int = 56;
+ pub const _SC_GETGR_R_SIZE_MAX: c_int = 70;
+ pub const _SC_GETPW_R_SIZE_MAX: c_int = 71;
+ pub const _SC_LOGIN_NAME_MAX: c_int = 73;
+ pub const _SC_MQ_PRIO_MAX: c_int = 75;
+ pub const _SC_THREAD_ATTR_STACKADDR: c_int = 82;
+ pub const _SC_THREAD_ATTR_STACKSIZE: c_int = 83;
+ pub const _SC_THREAD_DESTRUCTOR_ITERATIONS: c_int = 85;
+ pub const _SC_THREAD_KEYS_MAX: c_int = 86;
+ pub const _SC_THREAD_PRIO_INHERIT: c_int = 87;
+ pub const _SC_THREAD_PRIO_PROTECT: c_int = 88;
+ pub const _SC_THREAD_PRIORITY_SCHEDULING: c_int = 89;
+ pub const _SC_THREAD_PROCESS_SHARED: c_int = 90;
+ pub const _SC_THREAD_SAFE_FUNCTIONS: c_int = 91;
+ pub const _SC_THREAD_STACK_MIN: c_int = 93;
+ pub const _SC_THREAD_THREADS_MAX: c_int = 94;
+ pub const _SC_THREADS: c_int = 96;
+ pub const _SC_TTY_NAME_MAX: c_int = 101;
+ pub const _SC_ATEXIT_MAX: c_int = 107;
+ pub const _SC_XOPEN_CRYPT: c_int = 108;
+ pub const _SC_XOPEN_ENH_I18N: c_int = 109;
+ pub const _SC_XOPEN_LEGACY: c_int = 110;
+ pub const _SC_XOPEN_REALTIME: c_int = 111;
+ pub const _SC_XOPEN_REALTIME_THREADS: c_int = 112;
+ pub const _SC_XOPEN_SHM: c_int = 113;
+ pub const _SC_XOPEN_UNIX: c_int = 115;
+ pub const _SC_XOPEN_VERSION: c_int = 116;
+ pub const _SC_XOPEN_XCU_VERSION: c_int = 121;
pub const PTHREAD_CREATE_JOINABLE: c_int = 1;
pub const PTHREAD_CREATE_DETACHED: c_int = 2;
pub mod bsd44 {
use types::os::arch::c95::c_int;
- pub const MADV_NORMAL : c_int = 0;
- pub const MADV_RANDOM : c_int = 1;
- pub const MADV_SEQUENTIAL : c_int = 2;
- pub const MADV_WILLNEED : c_int = 3;
- pub const MADV_DONTNEED : c_int = 4;
- pub const MADV_FREE : c_int = 5;
- pub const MADV_ZERO_WIRED_PAGES : c_int = 6;
- pub const MADV_FREE_REUSABLE : c_int = 7;
- pub const MADV_FREE_REUSE : c_int = 8;
- pub const MADV_CAN_REUSE : c_int = 9;
-
- pub const MINCORE_INCORE : c_int = 0x1;
- pub const MINCORE_REFERENCED : c_int = 0x2;
- pub const MINCORE_MODIFIED : c_int = 0x4;
- pub const MINCORE_REFERENCED_OTHER : c_int = 0x8;
- pub const MINCORE_MODIFIED_OTHER : c_int = 0x10;
+ pub const MADV_NORMAL: c_int = 0;
+ pub const MADV_RANDOM: c_int = 1;
+ pub const MADV_SEQUENTIAL: c_int = 2;
+ pub const MADV_WILLNEED: c_int = 3;
+ pub const MADV_DONTNEED: c_int = 4;
+ pub const MADV_FREE: c_int = 5;
+ pub const MADV_ZERO_WIRED_PAGES: c_int = 6;
+ pub const MADV_FREE_REUSABLE: c_int = 7;
+ pub const MADV_FREE_REUSE: c_int = 8;
+ pub const MADV_CAN_REUSE: c_int = 9;
+
+ pub const MINCORE_INCORE: c_int = 0x1;
+ pub const MINCORE_REFERENCED: c_int = 0x2;
+ pub const MINCORE_MODIFIED: c_int = 0x4;
+ pub const MINCORE_REFERENCED_OTHER: c_int = 0x8;
+ pub const MINCORE_MODIFIED_OTHER: c_int = 0x10;
pub const AF_UNIX: c_int = 1;
pub const AF_INET: c_int = 2;
pub mod extra {
use types::os::arch::c95::c_int;
- pub const O_DSYNC : c_int = 4194304;
- pub const O_SYNC : c_int = 128;
- pub const O_NONBLOCK : c_int = 4;
- pub const F_GETPATH : c_int = 50;
- pub const F_FULLFSYNC : c_int = 51;
+ pub const O_DSYNC: c_int = 4194304;
+ pub const O_SYNC: c_int = 128;
+ pub const O_NONBLOCK: c_int = 4;
+ pub const F_GETPATH: c_int = 50;
+ pub const F_FULLFSYNC: c_int = 51;
+
+ pub const MAP_COPY: c_int = 0x0002;
+ pub const MAP_RENAME: c_int = 0x0020;
+ pub const MAP_NORESERVE: c_int = 0x0040;
+ pub const MAP_NOEXTEND: c_int = 0x0100;
+ pub const MAP_HASSEMAPHORE: c_int = 0x0200;
+ pub const MAP_NOCACHE: c_int = 0x0400;
+ pub const MAP_JIT: c_int = 0x0800;
+ pub const MAP_STACK: c_int = 0;
- pub const MAP_COPY : c_int = 0x0002;
- pub const MAP_RENAME : c_int = 0x0020;
- pub const MAP_NORESERVE : c_int = 0x0040;
- pub const MAP_NOEXTEND : c_int = 0x0100;
- pub const MAP_HASSEMAPHORE : c_int = 0x0200;
- pub const MAP_NOCACHE : c_int = 0x0400;
- pub const MAP_JIT : c_int = 0x0800;
- pub const MAP_STACK : c_int = 0;
-
- pub const IPPROTO_RAW : c_int = 255;
+ pub const IPPROTO_RAW: c_int = 255;
pub const SO_NREAD: c_int = 0x1020;
pub const SO_NKE: c_int = 0x1021;
pub mod sysconf {
use types::os::arch::c95::c_int;
- pub const _SC_ARG_MAX : c_int = 1;
- pub const _SC_CHILD_MAX : c_int = 2;
- pub const _SC_CLK_TCK : c_int = 3;
- pub const _SC_NGROUPS_MAX : c_int = 4;
- pub const _SC_OPEN_MAX : c_int = 5;
- pub const _SC_JOB_CONTROL : c_int = 6;
- pub const _SC_SAVED_IDS : c_int = 7;
- pub const _SC_VERSION : c_int = 8;
- pub const _SC_BC_BASE_MAX : c_int = 9;
- pub const _SC_BC_DIM_MAX : c_int = 10;
- pub const _SC_BC_SCALE_MAX : c_int = 11;
- pub const _SC_BC_STRING_MAX : c_int = 12;
- pub const _SC_COLL_WEIGHTS_MAX : c_int = 13;
- pub const _SC_EXPR_NEST_MAX : c_int = 14;
- pub const _SC_LINE_MAX : c_int = 15;
- pub const _SC_RE_DUP_MAX : c_int = 16;
- pub const _SC_2_VERSION : c_int = 17;
- pub const _SC_2_C_BIND : c_int = 18;
- pub const _SC_2_C_DEV : c_int = 19;
- pub const _SC_2_CHAR_TERM : c_int = 20;
- pub const _SC_2_FORT_DEV : c_int = 21;
- pub const _SC_2_FORT_RUN : c_int = 22;
- pub const _SC_2_LOCALEDEF : c_int = 23;
- pub const _SC_2_SW_DEV : c_int = 24;
- pub const _SC_2_UPE : c_int = 25;
- pub const _SC_STREAM_MAX : c_int = 26;
- pub const _SC_TZNAME_MAX : c_int = 27;
- pub const _SC_ASYNCHRONOUS_IO : c_int = 28;
- pub const _SC_PAGESIZE : c_int = 29;
- pub const _SC_MEMLOCK : c_int = 30;
- pub const _SC_MEMLOCK_RANGE : c_int = 31;
- pub const _SC_MEMORY_PROTECTION : c_int = 32;
- pub const _SC_MESSAGE_PASSING : c_int = 33;
- pub const _SC_PRIORITIZED_IO : c_int = 34;
- pub const _SC_PRIORITY_SCHEDULING : c_int = 35;
- pub const _SC_REALTIME_SIGNALS : c_int = 36;
- pub const _SC_SEMAPHORES : c_int = 37;
- pub const _SC_FSYNC : c_int = 38;
- pub const _SC_SHARED_MEMORY_OBJECTS : c_int = 39;
- pub const _SC_SYNCHRONIZED_IO : c_int = 40;
- pub const _SC_TIMERS : c_int = 41;
- pub const _SC_AIO_LISTIO_MAX : c_int = 42;
- pub const _SC_AIO_MAX : c_int = 43;
- pub const _SC_AIO_PRIO_DELTA_MAX : c_int = 44;
- pub const _SC_DELAYTIMER_MAX : c_int = 45;
- pub const _SC_MQ_OPEN_MAX : c_int = 46;
- pub const _SC_MAPPED_FILES : c_int = 47;
- pub const _SC_RTSIG_MAX : c_int = 48;
- pub const _SC_SEM_NSEMS_MAX : c_int = 49;
- pub const _SC_SEM_VALUE_MAX : c_int = 50;
- pub const _SC_SIGQUEUE_MAX : c_int = 51;
- pub const _SC_TIMER_MAX : c_int = 52;
- pub const _SC_NPROCESSORS_CONF : c_int = 57;
- pub const _SC_NPROCESSORS_ONLN : c_int = 58;
- pub const _SC_2_PBS : c_int = 59;
- pub const _SC_2_PBS_ACCOUNTING : c_int = 60;
- pub const _SC_2_PBS_CHECKPOINT : c_int = 61;
- pub const _SC_2_PBS_LOCATE : c_int = 62;
- pub const _SC_2_PBS_MESSAGE : c_int = 63;
- pub const _SC_2_PBS_TRACK : c_int = 64;
- pub const _SC_ADVISORY_INFO : c_int = 65;
- pub const _SC_BARRIERS : c_int = 66;
- pub const _SC_CLOCK_SELECTION : c_int = 67;
- pub const _SC_CPUTIME : c_int = 68;
- pub const _SC_FILE_LOCKING : c_int = 69;
- pub const _SC_HOST_NAME_MAX : c_int = 72;
- pub const _SC_MONOTONIC_CLOCK : c_int = 74;
- pub const _SC_READER_WRITER_LOCKS : c_int = 76;
- pub const _SC_REGEXP : c_int = 77;
- pub const _SC_SHELL : c_int = 78;
- pub const _SC_SPAWN : c_int = 79;
- pub const _SC_SPIN_LOCKS : c_int = 80;
- pub const _SC_SPORADIC_SERVER : c_int = 81;
- pub const _SC_THREAD_CPUTIME : c_int = 84;
- pub const _SC_THREAD_SPORADIC_SERVER : c_int = 92;
- pub const _SC_TIMEOUTS : c_int = 95;
- pub const _SC_TRACE : c_int = 97;
- pub const _SC_TRACE_EVENT_FILTER : c_int = 98;
- pub const _SC_TRACE_INHERIT : c_int = 99;
- pub const _SC_TRACE_LOG : c_int = 100;
- pub const _SC_TYPED_MEMORY_OBJECTS : c_int = 102;
- pub const _SC_V6_ILP32_OFF32 : c_int = 103;
- pub const _SC_V6_ILP32_OFFBIG : c_int = 104;
- pub const _SC_V6_LP64_OFF64 : c_int = 105;
- pub const _SC_V6_LPBIG_OFFBIG : c_int = 106;
- pub const _SC_IPV6 : c_int = 118;
- pub const _SC_RAW_SOCKETS : c_int = 119;
- pub const _SC_SYMLOOP_MAX : c_int = 120;
- pub const _SC_PAGE_SIZE : c_int = _SC_PAGESIZE;
- pub const _SC_XOPEN_STREAMS : c_int = 114;
- pub const _SC_XBS5_ILP32_OFF32 : c_int = 122;
- pub const _SC_XBS5_ILP32_OFFBIG : c_int = 123;
- pub const _SC_XBS5_LP64_OFF64 : c_int = 124;
- pub const _SC_XBS5_LPBIG_OFFBIG : c_int = 125;
- pub const _SC_SS_REPL_MAX : c_int = 126;
- pub const _SC_TRACE_EVENT_NAME_MAX : c_int = 127;
- pub const _SC_TRACE_NAME_MAX : c_int = 128;
- pub const _SC_TRACE_SYS_MAX : c_int = 129;
- pub const _SC_TRACE_USER_EVENT_MAX : c_int = 130;
- pub const _SC_PASS_MAX : c_int = 131;
+ pub const _SC_ARG_MAX: c_int = 1;
+ pub const _SC_CHILD_MAX: c_int = 2;
+ pub const _SC_CLK_TCK: c_int = 3;
+ pub const _SC_NGROUPS_MAX: c_int = 4;
+ pub const _SC_OPEN_MAX: c_int = 5;
+ pub const _SC_JOB_CONTROL: c_int = 6;
+ pub const _SC_SAVED_IDS: c_int = 7;
+ pub const _SC_VERSION: c_int = 8;
+ pub const _SC_BC_BASE_MAX: c_int = 9;
+ pub const _SC_BC_DIM_MAX: c_int = 10;
+ pub const _SC_BC_SCALE_MAX: c_int = 11;
+ pub const _SC_BC_STRING_MAX: c_int = 12;
+ pub const _SC_COLL_WEIGHTS_MAX: c_int = 13;
+ pub const _SC_EXPR_NEST_MAX: c_int = 14;
+ pub const _SC_LINE_MAX: c_int = 15;
+ pub const _SC_RE_DUP_MAX: c_int = 16;
+ pub const _SC_2_VERSION: c_int = 17;
+ pub const _SC_2_C_BIND: c_int = 18;
+ pub const _SC_2_C_DEV: c_int = 19;
+ pub const _SC_2_CHAR_TERM: c_int = 20;
+ pub const _SC_2_FORT_DEV: c_int = 21;
+ pub const _SC_2_FORT_RUN: c_int = 22;
+ pub const _SC_2_LOCALEDEF: c_int = 23;
+ pub const _SC_2_SW_DEV: c_int = 24;
+ pub const _SC_2_UPE: c_int = 25;
+ pub const _SC_STREAM_MAX: c_int = 26;
+ pub const _SC_TZNAME_MAX: c_int = 27;
+ pub const _SC_ASYNCHRONOUS_IO: c_int = 28;
+ pub const _SC_PAGESIZE: c_int = 29;
+ pub const _SC_MEMLOCK: c_int = 30;
+ pub const _SC_MEMLOCK_RANGE: c_int = 31;
+ pub const _SC_MEMORY_PROTECTION: c_int = 32;
+ pub const _SC_MESSAGE_PASSING: c_int = 33;
+ pub const _SC_PRIORITIZED_IO: c_int = 34;
+ pub const _SC_PRIORITY_SCHEDULING: c_int = 35;
+ pub const _SC_REALTIME_SIGNALS: c_int = 36;
+ pub const _SC_SEMAPHORES: c_int = 37;
+ pub const _SC_FSYNC: c_int = 38;
+ pub const _SC_SHARED_MEMORY_OBJECTS: c_int = 39;
+ pub const _SC_SYNCHRONIZED_IO: c_int = 40;
+ pub const _SC_TIMERS: c_int = 41;
+ pub const _SC_AIO_LISTIO_MAX: c_int = 42;
+ pub const _SC_AIO_MAX: c_int = 43;
+ pub const _SC_AIO_PRIO_DELTA_MAX: c_int = 44;
+ pub const _SC_DELAYTIMER_MAX: c_int = 45;
+ pub const _SC_MQ_OPEN_MAX: c_int = 46;
+ pub const _SC_MAPPED_FILES: c_int = 47;
+ pub const _SC_RTSIG_MAX: c_int = 48;
+ pub const _SC_SEM_NSEMS_MAX: c_int = 49;
+ pub const _SC_SEM_VALUE_MAX: c_int = 50;
+ pub const _SC_SIGQUEUE_MAX: c_int = 51;
+ pub const _SC_TIMER_MAX: c_int = 52;
+ pub const _SC_NPROCESSORS_CONF: c_int = 57;
+ pub const _SC_NPROCESSORS_ONLN: c_int = 58;
+ pub const _SC_2_PBS: c_int = 59;
+ pub const _SC_2_PBS_ACCOUNTING: c_int = 60;
+ pub const _SC_2_PBS_CHECKPOINT: c_int = 61;
+ pub const _SC_2_PBS_LOCATE: c_int = 62;
+ pub const _SC_2_PBS_MESSAGE: c_int = 63;
+ pub const _SC_2_PBS_TRACK: c_int = 64;
+ pub const _SC_ADVISORY_INFO: c_int = 65;
+ pub const _SC_BARRIERS: c_int = 66;
+ pub const _SC_CLOCK_SELECTION: c_int = 67;
+ pub const _SC_CPUTIME: c_int = 68;
+ pub const _SC_FILE_LOCKING: c_int = 69;
+ pub const _SC_HOST_NAME_MAX: c_int = 72;
+ pub const _SC_MONOTONIC_CLOCK: c_int = 74;
+ pub const _SC_READER_WRITER_LOCKS: c_int = 76;
+ pub const _SC_REGEXP: c_int = 77;
+ pub const _SC_SHELL: c_int = 78;
+ pub const _SC_SPAWN: c_int = 79;
+ pub const _SC_SPIN_LOCKS: c_int = 80;
+ pub const _SC_SPORADIC_SERVER: c_int = 81;
+ pub const _SC_THREAD_CPUTIME: c_int = 84;
+ pub const _SC_THREAD_SPORADIC_SERVER: c_int = 92;
+ pub const _SC_TIMEOUTS: c_int = 95;
+ pub const _SC_TRACE: c_int = 97;
+ pub const _SC_TRACE_EVENT_FILTER: c_int = 98;
+ pub const _SC_TRACE_INHERIT: c_int = 99;
+ pub const _SC_TRACE_LOG: c_int = 100;
+ pub const _SC_TYPED_MEMORY_OBJECTS: c_int = 102;
+ pub const _SC_V6_ILP32_OFF32: c_int = 103;
+ pub const _SC_V6_ILP32_OFFBIG: c_int = 104;
+ pub const _SC_V6_LP64_OFF64: c_int = 105;
+ pub const _SC_V6_LPBIG_OFFBIG: c_int = 106;
+ pub const _SC_IPV6: c_int = 118;
+ pub const _SC_RAW_SOCKETS: c_int = 119;
+ pub const _SC_SYMLOOP_MAX: c_int = 120;
+ pub const _SC_PAGE_SIZE: c_int = _SC_PAGESIZE;
+ pub const _SC_XOPEN_STREAMS: c_int = 114;
+ pub const _SC_XBS5_ILP32_OFF32: c_int = 122;
+ pub const _SC_XBS5_ILP32_OFFBIG: c_int = 123;
+ pub const _SC_XBS5_LP64_OFF64: c_int = 124;
+ pub const _SC_XBS5_LPBIG_OFFBIG: c_int = 125;
+ pub const _SC_SS_REPL_MAX: c_int = 126;
+ pub const _SC_TRACE_EVENT_NAME_MAX: c_int = 127;
+ pub const _SC_TRACE_NAME_MAX: c_int = 128;
+ pub const _SC_TRACE_SYS_MAX: c_int = 129;
+ pub const _SC_TRACE_USER_EVENT_MAX: c_int = 130;
+ pub const _SC_PASS_MAX: c_int = 131;
pub const _PC_NAME_MAX: c_int = 4;
pub const _PC_PATH_MAX: c_int = 5;
use types::os::arch::c95::{c_char, c_int, c_long, size_t};
extern {
- pub fn fopen(filename: *const c_char,
- mode: *const c_char) -> *mut FILE;
- pub fn freopen(filename: *const c_char, mode: *const c_char,
+ pub fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE;
+ pub fn freopen(filename: *const c_char,
+ mode: *const c_char,
file: *mut FILE)
-> *mut FILE;
pub fn fflush(file: *mut FILE) -> c_int;
pub fn fclose(file: *mut FILE) -> c_int;
pub fn remove(filename: *const c_char) -> c_int;
- pub fn rename(oldname: *const c_char,
- newname: *const c_char) -> c_int;
+ pub fn rename(oldname: *const c_char, newname: *const c_char) -> c_int;
pub fn tmpfile() -> *mut FILE;
pub fn setvbuf(stream: *mut FILE,
buffer: *mut c_char,
pub fn setbuf(stream: *mut FILE, buf: *mut c_char);
// Omitted: printf and scanf variants.
pub fn fgetc(stream: *mut FILE) -> c_int;
- pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE)
- -> *mut c_char;
+ pub fn fgets(buf: *mut c_char, n: c_int, stream: *mut FILE) -> *mut c_char;
pub fn fputc(c: c_int, stream: *mut FILE) -> c_int;
- pub fn fputs(s: *const c_char, stream: *mut FILE)-> c_int;
+ pub fn fputs(s: *const c_char, stream: *mut FILE) -> c_int;
// Omitted: getc, getchar (might be macros).
// Omitted: gets, so ridiculously unsafe that it should not
nobj: size_t,
stream: *mut FILE)
-> size_t;
- pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int)
- -> c_int;
+ pub fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int;
pub fn ftell(stream: *mut FILE) -> c_long;
pub fn rewind(stream: *mut FILE);
pub fn fgetpos(stream: *mut FILE, ptr: *mut fpos_t) -> c_int;
use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_double, c_int};
use types::os::arch::c95::{c_long, c_uint, c_ulong};
- use types::os::arch::c95::{size_t};
+ use types::os::arch::c95::size_t;
extern {
pub fn abs(i: c_int) -> c_int;
// Omitted: div, ldiv (return pub type incomplete).
pub fn atof(s: *const c_char) -> c_double;
pub fn atoi(s: *const c_char) -> c_int;
- pub fn strtod(s: *const c_char,
- endp: *mut *mut c_char) -> c_double;
- pub fn strtol(s: *const c_char,
- endp: *mut *mut c_char, base: c_int) -> c_long;
- pub fn strtoul(s: *const c_char, endp: *mut *mut c_char,
- base: c_int) -> c_ulong;
+ pub fn strtod(s: *const c_char, endp: *mut *mut c_char) -> c_double;
+ pub fn strtol(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_long;
+ pub fn strtoul(s: *const c_char, endp: *mut *mut c_char, base: c_int) -> c_ulong;
pub fn calloc(nobj: size_t, size: size_t) -> *mut c_void;
pub fn malloc(size: size_t) -> *mut c_void;
pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
/// Exits the running program in a possibly dangerous manner.
///
- /// # Unsafety
+ /// # Safety
///
/// While this forces your program to exit, it does so in a way that has
/// consequences. This will skip all unwinding code, which means that anything
/// ```
pub fn exit(status: c_int) -> !;
pub fn _exit(status: c_int) -> !;
- pub fn atexit(cb: extern fn()) -> c_int;
+ pub fn atexit(cb: extern "C" fn()) -> c_int;
pub fn system(s: *const c_char) -> c_int;
pub fn getenv(s: *const c_char) -> *mut c_char;
// Omitted: bsearch, qsort
pub mod string {
use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, size_t};
- use types::os::arch::c95::{wchar_t};
+ use types::os::arch::c95::wchar_t;
extern {
- pub fn strcpy(dst: *mut c_char,
- src: *const c_char) -> *mut c_char;
- pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t)
- -> *mut c_char;
+ pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char;
+ pub fn strncpy(dst: *mut c_char, src: *const c_char, n: size_t) -> *mut c_char;
pub fn strcat(s: *mut c_char, ct: *const c_char) -> *mut c_char;
- pub fn strncat(s: *mut c_char, ct: *const c_char,
- n: size_t) -> *mut c_char;
+ pub fn strncat(s: *mut c_char, ct: *const c_char, n: size_t) -> *mut c_char;
pub fn strcmp(cs: *const c_char, ct: *const c_char) -> c_int;
- pub fn strncmp(cs: *const c_char, ct: *const c_char,
- n: size_t) -> c_int;
+ pub fn strncmp(cs: *const c_char, ct: *const c_char, n: size_t) -> c_int;
pub fn strcoll(cs: *const c_char, ct: *const c_char) -> c_int;
pub fn strchr(cs: *const c_char, c: c_int) -> *mut c_char;
pub fn strrchr(cs: *const c_char, c: c_int) -> *mut c_char;
pub fn strspn(cs: *const c_char, ct: *const c_char) -> size_t;
pub fn strcspn(cs: *const c_char, ct: *const c_char) -> size_t;
- pub fn strpbrk(cs: *const c_char,
- ct: *const c_char) -> *mut c_char;
- pub fn strstr(cs: *const c_char,
- ct: *const c_char) -> *mut c_char;
+ pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
+ pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
pub fn strlen(cs: *const c_char) -> size_t;
pub fn strerror(n: c_int) -> *mut c_char;
pub fn strtok(s: *mut c_char, t: *const c_char) -> *mut c_char;
- pub fn strxfrm(s: *mut c_char, ct: *const c_char,
- n: size_t) -> size_t;
+ pub fn strxfrm(s: *mut c_char, ct: *const c_char, n: size_t) -> size_t;
pub fn wcslen(buf: *const wchar_t) -> size_t;
// Omitted: memcpy, memmove, memset (provided by LLVM)
// These are fine to execute on the Rust stack. They must be,
// in fact, because LLVM generates calls to them!
- pub fn memcmp(cx: *const c_void, ct: *const c_void,
- n: size_t) -> c_int;
- pub fn memchr(cx: *const c_void, c: c_int,
- n: size_t) -> *mut c_void;
+ pub fn memcmp(cx: *const c_void, ct: *const c_void, n: size_t) -> c_int;
+ pub fn memchr(cx: *const c_void, c: c_int, n: size_t) -> *mut c_void;
}
}
}
extern {
#[link_name = "_popen"]
- pub fn popen(command: *const c_char,
- mode: *const c_char) -> *mut FILE;
+ pub fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE;
#[link_name = "_pclose"]
pub fn pclose(stream: *mut FILE) -> c_int;
#[link_name = "_fdopen"]
use types::os::arch::c95::{c_int, c_char, wchar_t};
extern {
#[link_name = "_open"]
- pub fn open(path: *const c_char, oflag: c_int, mode: c_int)
- -> c_int;
+ pub fn open(path: *const c_char, oflag: c_int, mode: c_int) -> c_int;
#[link_name = "_wopen"]
- pub fn wopen(path: *const wchar_t, oflag: c_int, mode: c_int)
- -> c_int;
+ pub fn wopen(path: *const wchar_t, oflag: c_int, mode: c_int) -> c_int;
#[link_name = "_creat"]
pub fn creat(path: *const c_char, mode: c_int) -> c_int;
}
pub mod unistd {
use types::common::c95::c_void;
- use types::os::arch::c95::{c_int, c_uint, c_char,
- c_long, size_t};
+ use types::os::arch::c95::{c_int, c_uint, c_char, c_long, size_t};
use types::os::arch::c99::intptr_t;
extern {
#[link_name = "_dup2"]
pub fn dup2(src: c_int, dst: c_int) -> c_int;
#[link_name = "_execv"]
- pub fn execv(prog: *const c_char,
- argv: *const *const c_char) -> intptr_t;
+ pub fn execv(prog: *const c_char, argv: *const *const c_char) -> intptr_t;
#[link_name = "_execve"]
- pub fn execve(prog: *const c_char, argv: *const *const c_char,
+ pub fn execve(prog: *const c_char,
+ argv: *const *const c_char,
envp: *const *const c_char)
-> c_int;
#[link_name = "_execvp"]
- pub fn execvp(c: *const c_char,
- argv: *const *const c_char) -> c_int;
+ pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int;
#[link_name = "_execvpe"]
- pub fn execvpe(c: *const c_char, argv: *const *const c_char,
- envp: *const *const c_char) -> c_int;
+ pub fn execvpe(c: *const c_char,
+ argv: *const *const c_char,
+ envp: *const *const c_char)
+ -> c_int;
#[link_name = "_getcwd"]
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
#[link_name = "_getpid"]
#[link_name = "_isatty"]
pub fn isatty(fd: c_int) -> c_int;
#[link_name = "_lseek"]
- pub fn lseek(fd: c_int, offset: c_long, origin: c_int)
- -> c_long;
+ pub fn lseek(fd: c_int, offset: c_long, origin: c_int) -> c_long;
#[link_name = "_pipe"]
- pub fn pipe(fds: *mut c_int, psize: c_uint, textmode: c_int)
- -> c_int;
+ pub fn pipe(fds: *mut c_int, psize: c_uint, textmode: c_int) -> c_int;
#[link_name = "_read"]
- pub fn read(fd: c_int, buf: *mut c_void, count: c_uint)
- -> c_int;
+ pub fn read(fd: c_int, buf: *mut c_void, count: c_uint) -> c_int;
#[link_name = "_rmdir"]
pub fn rmdir(path: *const c_char) -> c_int;
#[link_name = "_unlink"]
pub fn unlink(c: *const c_char) -> c_int;
#[link_name = "_write"]
- pub fn write(fd: c_int, buf: *const c_void,
- count: c_uint) -> c_int;
+ pub fn write(fd: c_int, buf: *const c_void, count: c_uint) -> c_int;
}
}
pub fn chmod(path: *const c_char, mode: mode_t) -> c_int;
pub fn fchmod(fd: c_int, mode: mode_t) -> c_int;
- #[cfg(any(target_os = "linux",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "android",
- target_os = "ios",
- target_os = "nacl"))]
- pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
-
- #[cfg(target_os = "macos")]
- #[link_name = "fstat64"]
+ #[cfg_attr(target_os = "macos", link_name = "fstat64")]
+ #[cfg_attr(target_os = "netbsd", link_name = "__fstat50")]
pub fn fstat(fildes: c_int, buf: *mut stat) -> c_int;
pub fn mkdir(path: *const c_char, mode: mode_t) -> c_int;
#[cfg(not(target_os = "nacl"))]
pub fn mkfifo(path: *const c_char, mode: mode_t) -> c_int;
- #[cfg(any(target_os = "linux",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "android",
- target_os = "ios",
- target_os = "nacl"))]
- pub fn stat(path: *const c_char, buf: *mut stat) -> c_int;
-
- #[cfg(target_os = "macos")]
- #[link_name = "stat64"]
+ #[cfg_attr(target_os = "macos", link_name = "stat64")]
+ #[cfg_attr(target_os = "netbsd", link_name = "__stat50")]
pub fn stat(path: *const c_char, buf: *mut stat) -> c_int;
}
}
use types::os::arch::c95::{c_char, c_int};
extern {
- pub fn popen(command: *const c_char,
- mode: *const c_char) -> *mut FILE;
+ pub fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE;
pub fn pclose(stream: *mut FILE) -> c_int;
pub fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE;
pub fn fileno(stream: *mut FILE) -> c_int;
extern {
#[cfg(any(target_os = "macos",
target_os = "ios"))]
- pub fn open(path: *const ::c_char, oflag: ::c_int, ...)
- -> ::c_int;
+ pub fn open(path: *const ::c_char, oflag: ::c_int, ...) -> ::c_int;
#[cfg(not(any(target_os = "macos",
target_os = "ios")))]
- pub fn open(path: *const ::c_char, oflag: ::c_int, mode: ::mode_t)
- -> ::c_int;
+ pub fn open(path: *const ::c_char, oflag: ::c_int, mode: ::mode_t) -> ::c_int;
}
}
#[cfg(any(target_os = "macos",
target_os = "ios"))]
#[inline]
- pub unsafe extern fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
+ pub unsafe extern "C" fn open(path: *const c_char,
+ oflag: c_int,
+ mode: mode_t)
+ -> c_int {
use types::os::arch::c95::c_uint;
open_shim::open(path, oflag, mode as c_uint)
}
#[cfg(not(any(target_os = "macos",
target_os = "ios")))]
#[inline]
- pub unsafe extern fn open(path: *const c_char, oflag: c_int, mode: mode_t) -> c_int {
+ pub unsafe extern "C" fn open(path: *const c_char,
+ oflag: c_int,
+ mode: mode_t)
+ -> c_int {
open_shim::open(path, oflag, mode)
}
#[link_name="rust_opendir"]
pub fn opendir(dirname: *const c_char) -> *mut DIR;
#[link_name="rust_readdir_r"]
- pub fn readdir_r(dirp: *mut DIR, entry: *mut dirent_t,
- result: *mut *mut dirent_t) -> c_int;
+ pub fn readdir_r(dirp: *mut DIR,
+ entry: *mut dirent_t,
+ result: *mut *mut dirent_t)
+ -> c_int;
}
extern {
pub mod unistd {
use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_int, c_long, c_uint};
- use types::os::arch::c95::{size_t};
+ use types::os::arch::c95::size_t;
use types::os::common::posix01::timespec;
use types::os::arch::posix01::utimbuf;
use types::os::arch::posix88::{gid_t, off_t, pid_t};
pub fn access(path: *const c_char, amode: c_int) -> c_int;
pub fn alarm(seconds: c_uint) -> c_uint;
pub fn chdir(dir: *const c_char) -> c_int;
- pub fn chown(path: *const c_char, uid: uid_t,
- gid: gid_t) -> c_int;
+ pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int;
pub fn close(fd: c_int) -> c_int;
pub fn dup(fd: c_int) -> c_int;
pub fn dup2(src: c_int, dst: c_int) -> c_int;
- pub fn execv(prog: *const c_char,
- argv: *const *const c_char) -> c_int;
- pub fn execve(prog: *const c_char, argv: *const *const c_char,
+ pub fn execv(prog: *const c_char, argv: *const *const c_char) -> c_int;
+ pub fn execve(prog: *const c_char,
+ argv: *const *const c_char,
envp: *const *const c_char)
-> c_int;
- pub fn execvp(c: *const c_char,
- argv: *const *const c_char) -> c_int;
+ pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int;
pub fn fork() -> pid_t;
pub fn fpathconf(filedes: c_int, name: c_int) -> c_long;
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
pub fn getegid() -> gid_t;
pub fn geteuid() -> uid_t;
pub fn getgid() -> gid_t;
- pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t)
- -> c_int;
+ pub fn getgroups(ngroups_max: c_int, groups: *mut gid_t) -> c_int;
pub fn getlogin() -> *mut c_char;
// GNU getopt(3) modifies its arguments despite the
// char * const [] prototype; see the manpage.
- pub fn getopt(argc: c_int, argv: *mut *mut c_char,
- optstr: *const c_char) -> c_int;
+ pub fn getopt(argc: c_int, argv: *mut *mut c_char, optstr: *const c_char) -> c_int;
pub fn getpgrp() -> pid_t;
pub fn getpid() -> pid_t;
pub fn getppid() -> pid_t;
pub fn getsid(pid: pid_t) -> pid_t;
pub fn isatty(fd: c_int) -> c_int;
pub fn link(src: *const c_char, dst: *const c_char) -> c_int;
- pub fn lseek(fd: c_int, offset: off_t, whence: c_int)
- -> off_t;
+ pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t;
pub fn pathconf(path: *mut c_char, name: c_int) -> c_long;
pub fn pause() -> c_int;
pub fn pipe(fds: *mut c_int) -> c_int;
- pub fn read(fd: c_int, buf: *mut c_void, count: size_t)
- -> ssize_t;
+ pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t;
pub fn rmdir(path: *const c_char) -> c_int;
pub fn setgid(gid: gid_t) -> c_int;
pub fn setpgid(pid: pid_t, pgid: pid_t) -> c_int;
pub fn setuid(uid: uid_t) -> c_int;
pub fn sleep(secs: c_uint) -> c_uint;
pub fn usleep(secs: c_uint) -> c_int;
- pub fn nanosleep(rqtp: *const timespec,
- rmtp: *mut timespec) -> c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__nanosleep50")]
+ pub fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int;
pub fn sysconf(name: c_int) -> c_long;
pub fn tcgetpgrp(fd: c_int) -> pid_t;
pub fn ttyname(fd: c_int) -> *mut c_char;
pub fn unlink(c: *const c_char) -> c_int;
pub fn wait(status: *const c_int) -> pid_t;
- pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int)
- -> pid_t;
- pub fn write(fd: c_int, buf: *const c_void, count: size_t)
- -> ssize_t;
- pub fn pread(fd: c_int, buf: *mut c_void, count: size_t,
- offset: off_t) -> ssize_t;
- pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t,
- offset: off_t) -> ssize_t;
+ pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) -> pid_t;
+ pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t;
+ pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, offset: off_t) -> ssize_t;
+ pub fn pwrite(fd: c_int,
+ buf: *const c_void,
+ count: size_t,
+ offset: off_t)
+ -> ssize_t;
+ #[cfg_attr(target_os = "netbsd", link_name = "__utime50")]
pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int;
}
#[cfg(target_os = "nacl")]
extern {
pub fn access(path: *const c_char, amode: c_int) -> c_int;
pub fn chdir(dir: *const c_char) -> c_int;
- pub fn chown(path: *const c_char, uid: uid_t,
- gid: gid_t) -> c_int;
+ pub fn chown(path: *const c_char, uid: uid_t, gid: gid_t) -> c_int;
pub fn close(fd: c_int) -> c_int;
pub fn dup(fd: c_int) -> c_int;
pub fn dup2(src: c_int, dst: c_int) -> c_int;
- pub fn execv(prog: *const c_char,
- argv: *const *const c_char) -> c_int;
- pub fn execve(prog: *const c_char, argv: *const *const c_char,
+ pub fn execv(prog: *const c_char, argv: *const *const c_char) -> c_int;
+ pub fn execve(prog: *const c_char,
+ argv: *const *const c_char,
envp: *const *const c_char)
-> c_int;
- pub fn execvp(c: *const c_char,
- argv: *const *const c_char) -> c_int;
+ pub fn execvp(c: *const c_char, argv: *const *const c_char) -> c_int;
pub fn fork() -> pid_t;
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
pub fn getegid() -> gid_t;
pub fn geteuid() -> uid_t;
pub fn getgid() -> gid_t;
pub fn getlogin() -> *mut c_char;
- pub fn getopt(argc: c_int, argv: *const *const c_char,
- optstr: *const c_char) -> c_int;
+ pub fn getopt(argc: c_int,
+ argv: *const *const c_char,
+ optstr: *const c_char)
+ -> c_int;
pub fn getuid() -> uid_t;
pub fn getsid(pid: pid_t) -> pid_t;
pub fn isatty(fd: c_int) -> c_int;
pub fn link(src: *const c_char, dst: *const c_char) -> c_int;
- pub fn lseek(fd: c_int, offset: off_t, whence: c_int)
- -> off_t;
+ pub fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t;
pub fn pipe(fds: *mut c_int) -> c_int;
- pub fn read(fd: c_int, buf: *mut c_void, count: size_t)
- -> ssize_t;
+ pub fn read(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t;
pub fn rmdir(path: *const c_char) -> c_int;
pub fn setgid(gid: gid_t) -> c_int;
pub fn setuid(uid: uid_t) -> c_int;
pub fn sleep(secs: c_uint) -> c_uint;
pub fn usleep(secs: c_uint) -> c_int;
- pub fn nanosleep(rqtp: *const timespec,
- rmtp: *mut timespec) -> c_int;
+ pub fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> c_int;
pub fn sysconf(name: c_int) -> c_long;
pub fn ttyname(fd: c_int) -> *mut c_char;
pub fn unlink(c: *const c_char) -> c_int;
pub fn wait(status: *const c_int) -> pid_t;
- pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int)
- -> pid_t;
- pub fn write(fd: c_int, buf: *const c_void, count: size_t)
- -> ssize_t;
- pub fn pread(fd: c_int, buf: *mut c_void, count: size_t,
- offset: off_t) -> ssize_t;
- pub fn pwrite(fd: c_int, buf: *const c_void, count: size_t,
- offset: off_t) -> ssize_t;
+ pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int) -> pid_t;
+ pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t;
+ pub fn pread(fd: c_int, buf: *mut c_void, count: size_t, offset: off_t) -> ssize_t;
+ pub fn pwrite(fd: c_int,
+ buf: *const c_void,
+ count: size_t,
+ offset: off_t)
+ -> ssize_t;
pub fn utime(file: *const c_char, buf: *const utimbuf) -> c_int;
}
}
pub mod signal {
- use types::os::arch::c95::{c_int};
- use types::os::arch::posix88::{pid_t};
+ use types::os::arch::c95::c_int;
+ use types::os::arch::posix88::pid_t;
extern {
pub fn kill(pid: pid_t, sig: c_int) -> c_int;
}
pub mod mman {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{size_t, c_int, c_char};
use types::os::arch::posix88::{mode_t, off_t};
pub fn mlockall(flags: c_int) -> c_int;
pub fn munlockall() -> c_int;
- pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int)
- -> c_int;
+ pub fn mprotect(addr: *mut c_void, len: size_t, prot: c_int) -> c_int;
- pub fn msync(addr: *mut c_void, len: size_t, flags: c_int)
- -> c_int;
- pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t)
- -> c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__msync13")]
+ pub fn msync(addr: *mut c_void, len: size_t, flags: c_int) -> c_int;
+
+ pub fn shm_open(name: *const c_char, oflag: c_int, mode: mode_t) -> c_int;
pub fn shm_unlink(name: *const c_char) -> c_int;
}
use types::os::arch::posix01::stat;
extern {
- #[cfg(any(target_os = "linux",
- target_os = "freebsd",
- target_os = "dragonfly",
- target_os = "bitrig",
- target_os = "netbsd",
- target_os = "openbsd",
- target_os = "android",
- target_os = "ios",
- target_os = "nacl"))]
- pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int;
-
- #[cfg(target_os = "macos")]
- #[link_name = "lstat64"]
+ #[cfg_attr(target_os = "macos", link_name = "lstat64")]
+ #[cfg_attr(target_os = "netbsd", link_name = "__lstat50")]
pub fn lstat(path: *const c_char, buf: *mut stat) -> c_int;
}
}
use types::os::arch::posix88::{ssize_t, off_t};
extern {
- pub fn readlink(path: *const c_char,
- buf: *mut c_char,
- bufsz: size_t)
- -> ssize_t;
+ pub fn readlink(path: *const c_char, buf: *mut c_char, bufsz: size_t) -> ssize_t;
pub fn fsync(fd: c_int) -> c_int;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn fdatasync(fd: c_int) -> c_int;
- pub fn setenv(name: *const c_char, val: *const c_char,
- overwrite: c_int) -> c_int;
+ pub fn setenv(name: *const c_char, val: *const c_char, overwrite: c_int) -> c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__unsetenv13")]
pub fn unsetenv(name: *const c_char) -> c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__putenv50")]
pub fn putenv(string: *mut c_char) -> c_int;
- pub fn symlink(path1: *const c_char,
- path2: *const c_char) -> c_int;
+ pub fn symlink(path1: *const c_char, path2: *const c_char) -> c_int;
pub fn ftruncate(fd: c_int, length: off_t) -> c_int;
}
#[cfg(not(all(target_os = "android", any(target_arch = "arm",
target_arch = "x86"))))]
extern {
- pub fn signal(signum: c_int,
- handler: sighandler_t) -> sighandler_t;
+ pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t;
}
#[cfg(all(target_os = "android", any(target_arch = "arm",
target_arch = "x86")))]
extern {
#[link_name = "bsd_signal"]
- pub fn signal(signum: c_int,
- handler: sighandler_t) -> sighandler_t;
+ pub fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t;
}
}
pub mod glob {
use types::os::arch::c95::{c_char, c_int};
- use types::os::common::posix01::{glob_t};
+ use types::os::common::posix01::glob_t;
extern {
+ #[cfg_attr(target_os = "netbsd", link_name = "__glob30")]
pub fn glob(pattern: *const c_char,
flags: c_int,
errfunc: ::core::option::Option<extern "C" fn(epath: *const c_char,
errno: c_int) -> c_int>,
pglob: *mut glob_t);
+ #[cfg_attr(target_os = "netbsd", link_name = "__globfree30")]
pub fn globfree(pglob: *mut glob_t);
}
}
pub mod mman {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_int, size_t};
#[cfg(not(target_os = "nacl"))]
extern {
- pub fn posix_madvise(addr: *mut c_void,
- len: size_t,
- advice: c_int)
- -> c_int;
+ pub fn posix_madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int;
}
}
extern {
pub fn getrlimit(resource: c_int, rlim: *mut rlimit) -> c_int;
pub fn setrlimit(resource: c_int, rlim: *const rlimit) -> c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__getrusage50")]
pub fn getrusage(resource: c_int, usage: *mut rusage) -> c_int;
-
}
}
}
#[cfg(not(windows))]
pub mod bsd43 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::common::bsd44::{socklen_t, sockaddr, ifaddrs};
use types::os::arch::c95::{c_int, size_t};
use types::os::arch::posix88::ssize_t;
extern "system" {
+ #[cfg_attr(target_os = "netbsd", link_name = "__socket30")]
pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> c_int;
- pub fn connect(socket: c_int, address: *const sockaddr,
- len: socklen_t) -> c_int;
- pub fn bind(socket: c_int, address: *const sockaddr,
- address_len: socklen_t) -> c_int;
+
+ pub fn connect(socket: c_int, address: *const sockaddr, len: socklen_t) -> c_int;
+ pub fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> c_int;
pub fn listen(socket: c_int, backlog: c_int) -> c_int;
- pub fn accept(socket: c_int, address: *mut sockaddr,
- address_len: *mut socklen_t) -> c_int;
- pub fn getpeername(socket: c_int, address: *mut sockaddr,
- address_len: *mut socklen_t) -> c_int;
- pub fn getsockname(socket: c_int, address: *mut sockaddr,
- address_len: *mut socklen_t) -> c_int;
- pub fn setsockopt(socket: c_int, level: c_int, name: c_int,
+ pub fn accept(socket: c_int,
+ address: *mut sockaddr,
+ address_len: *mut socklen_t)
+ -> c_int;
+ pub fn getpeername(socket: c_int,
+ address: *mut sockaddr,
+ address_len: *mut socklen_t)
+ -> c_int;
+ pub fn getsockname(socket: c_int,
+ address: *mut sockaddr,
+ address_len: *mut socklen_t)
+ -> c_int;
+ pub fn setsockopt(socket: c_int,
+ level: c_int,
+ name: c_int,
value: *const c_void,
- option_len: socklen_t) -> c_int;
- pub fn recv(socket: c_int, buf: *mut c_void, len: size_t,
- flags: c_int) -> ssize_t;
- pub fn send(socket: c_int, buf: *const c_void, len: size_t,
- flags: c_int) -> ssize_t;
- pub fn recvfrom(socket: c_int, buf: *mut c_void, len: size_t,
- flags: c_int, addr: *mut sockaddr,
- addrlen: *mut socklen_t) -> ssize_t;
- pub fn sendto(socket: c_int, buf: *const c_void, len: size_t,
- flags: c_int, addr: *const sockaddr,
- addrlen: socklen_t) -> ssize_t;
+ option_len: socklen_t)
+ -> c_int;
+ pub fn recv(socket: c_int, buf: *mut c_void, len: size_t, flags: c_int) -> ssize_t;
+ pub fn send(socket: c_int, buf: *const c_void, len: size_t, flags: c_int) -> ssize_t;
+ pub fn recvfrom(socket: c_int,
+ buf: *mut c_void,
+ len: size_t,
+ flags: c_int,
+ addr: *mut sockaddr,
+ addrlen: *mut socklen_t)
+ -> ssize_t;
+ pub fn sendto(socket: c_int,
+ buf: *const c_void,
+ len: size_t,
+ flags: c_int,
+ addr: *const sockaddr,
+ addrlen: socklen_t)
+ -> ssize_t;
pub fn getifaddrs(ifap: *mut *mut ifaddrs) -> c_int;
pub fn freeifaddrs(ifa: *mut ifaddrs);
pub fn shutdown(socket: c_int, how: c_int) -> c_int;
#[cfg(windows)]
pub mod bsd43 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::common::bsd44::{socklen_t, sockaddr, SOCKET};
use types::os::arch::c95::c_int;
extern "system" {
pub fn socket(domain: c_int, ty: c_int, protocol: c_int) -> SOCKET;
- pub fn connect(socket: SOCKET, address: *const sockaddr,
- len: socklen_t) -> c_int;
- pub fn bind(socket: SOCKET, address: *const sockaddr,
- address_len: socklen_t) -> c_int;
+ pub fn connect(socket: SOCKET, address: *const sockaddr, len: socklen_t) -> c_int;
+ pub fn bind(socket: SOCKET, address: *const sockaddr, address_len: socklen_t) -> c_int;
pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
- pub fn accept(socket: SOCKET, address: *mut sockaddr,
- address_len: *mut socklen_t) -> SOCKET;
- pub fn getpeername(socket: SOCKET, address: *mut sockaddr,
- address_len: *mut socklen_t) -> c_int;
- pub fn getsockname(socket: SOCKET, address: *mut sockaddr,
- address_len: *mut socklen_t) -> c_int;
- pub fn setsockopt(socket: SOCKET, level: c_int, name: c_int,
+ pub fn accept(socket: SOCKET,
+ address: *mut sockaddr,
+ address_len: *mut socklen_t)
+ -> SOCKET;
+ pub fn getpeername(socket: SOCKET,
+ address: *mut sockaddr,
+ address_len: *mut socklen_t)
+ -> c_int;
+ pub fn getsockname(socket: SOCKET,
+ address: *mut sockaddr,
+ address_len: *mut socklen_t)
+ -> c_int;
+ pub fn setsockopt(socket: SOCKET,
+ level: c_int,
+ name: c_int,
value: *const c_void,
- option_len: socklen_t) -> c_int;
+ option_len: socklen_t)
+ -> c_int;
pub fn closesocket(socket: SOCKET) -> c_int;
- pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int,
- flags: c_int) -> c_int;
- pub fn send(socket: SOCKET, buf: *const c_void, len: c_int,
- flags: c_int) -> c_int;
- pub fn recvfrom(socket: SOCKET, buf: *mut c_void, len: c_int,
- flags: c_int, addr: *mut sockaddr,
- addrlen: *mut c_int) -> c_int;
- pub fn sendto(socket: SOCKET, buf: *const c_void, len: c_int,
- flags: c_int, addr: *const sockaddr,
- addrlen: c_int) -> c_int;
+ pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
+ pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int;
+ pub fn recvfrom(socket: SOCKET,
+ buf: *mut c_void,
+ len: c_int,
+ flags: c_int,
+ addr: *mut sockaddr,
+ addrlen: *mut c_int)
+ -> c_int;
+ pub fn sendto(socket: SOCKET,
+ buf: *const c_void,
+ len: c_int,
+ flags: c_int,
+ addr: *const sockaddr,
+ addrlen: c_int)
+ -> c_int;
pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
}
}
target_os = "netbsd",
target_os = "openbsd"))]
pub mod bsd44 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_char, c_uchar, c_int, c_uint, c_ulong, size_t};
extern {
sizep: *mut size_t)
-> c_int;
pub fn getdtablesize() -> c_int;
- pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int)
- -> c_int;
- pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar)
- -> c_int;
- pub fn realpath(pathname: *const c_char, resolved: *mut c_char)
- -> *mut c_char;
+ pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int;
+ pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) -> c_int;
+ pub fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char;
pub fn flock(fd: c_int, operation: c_int) -> c_int;
}
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod bsd44 {
- use types::common::c95::{c_void};
+ use types::common::c95::c_void;
use types::os::arch::c95::{c_uchar, c_int, size_t};
#[cfg(not(feature = "cargo-build"))]
use types::os::arch::c95::c_ulong;
pub fn ioctl(fd: c_int, request: c_int, ...) -> c_int;
#[cfg(not(feature = "cargo-build"))]
pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
- pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int)
- -> c_int;
- pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar)
- -> c_int;
+ pub fn madvise(addr: *mut c_void, len: size_t, advice: c_int) -> c_int;
+ pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar) -> c_int;
pub fn flock(fd: c_int, operation: c_int) -> c_int;
}
}
use types::os::arch::c95::{c_char, c_int};
extern {
- pub fn _NSGetExecutablePath(buf: *mut c_char, bufsize: *mut u32)
- -> c_int;
+ pub fn _NSGetExecutablePath(buf: *mut c_char, bufsize: *mut u32) -> c_int;
}
}
pub mod extra {
pub mod kernel32 {
- use types::os::arch::c95::{c_uint};
- use types::os::arch::extra::{BOOL, DWORD, SIZE_T, HMODULE,
- LPCWSTR, LPWSTR,
- LPWCH, LPDWORD, LPVOID,
- LPCVOID, LPOVERLAPPED,
- LPSECURITY_ATTRIBUTES,
- LPSTARTUPINFO,
- LPPROCESS_INFORMATION,
- LPMEMORY_BASIC_INFORMATION,
- LPSYSTEM_INFO, HANDLE, LPHANDLE,
- LARGE_INTEGER, PLARGE_INTEGER,
- LPFILETIME, LPWIN32_FIND_DATAW};
+ use types::os::arch::c95::c_uint;
+ use types::os::arch::extra::{BOOL, DWORD, SIZE_T, HMODULE, LPCWSTR, LPWSTR, LPWCH,
+ LPDWORD, LPVOID, LPCVOID, LPOVERLAPPED,
+ LPSECURITY_ATTRIBUTES, LPSTARTUPINFO,
+ LPPROCESS_INFORMATION, LPMEMORY_BASIC_INFORMATION,
+ LPSYSTEM_INFO, HANDLE, LPHANDLE, LARGE_INTEGER,
+ PLARGE_INTEGER, LPFILETIME, LPWIN32_FIND_DATAW};
extern "system" {
- pub fn GetEnvironmentVariableW(n: LPCWSTR,
- v: LPWSTR,
- nsize: DWORD)
- -> DWORD;
- pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
- -> BOOL;
+ pub fn GetEnvironmentVariableW(n: LPCWSTR, v: LPWSTR, nsize: DWORD) -> DWORD;
+ pub fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL;
pub fn GetEnvironmentStringsW() -> LPWCH;
pub fn FreeEnvironmentStringsW(env_ptr: LPWCH) -> BOOL;
pub fn GetModuleFileNameW(hModule: HMODULE,
nSize: DWORD)
-> DWORD;
pub fn CreateDirectoryW(lpPathName: LPCWSTR,
- lpSecurityAttributes:
- LPSECURITY_ATTRIBUTES)
+ lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
-> BOOL;
pub fn CopyFileW(lpExistingFileName: LPCWSTR,
lpNewFileName: LPCWSTR,
-> BOOL;
pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
- pub fn GetCurrentDirectoryW(nBufferLength: DWORD,
- lpBuffer: LPWSTR)
- -> DWORD;
+ pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn GetLastError() -> DWORD;
- pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW)
+ pub fn FindFirstFileW(fileName: LPCWSTR,
+ findFileData: LPWIN32_FIND_DATAW)
-> HANDLE;
- pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW)
- -> BOOL;
+ pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL;
pub fn FindClose(findFile: HANDLE) -> BOOL;
pub fn DuplicateHandle(hSourceProcessHandle: HANDLE,
hSourceHandle: HANDLE,
pub fn GetCurrentProcess() -> HANDLE;
pub fn CreateProcessW(lpApplicationName: LPCWSTR,
lpCommandLine: LPWSTR,
- lpProcessAttributes:
- LPSECURITY_ATTRIBUTES,
- lpThreadAttributes:
- LPSECURITY_ATTRIBUTES,
+ lpProcessAttributes: LPSECURITY_ATTRIBUTES,
+ lpThreadAttributes: LPSECURITY_ATTRIBUTES,
bInheritHandles: BOOL,
dwCreationFlags: DWORD,
lpEnvironment: LPVOID,
lpCurrentDirectory: LPCWSTR,
lpStartupInfo: LPSTARTUPINFO,
- lpProcessInformation:
- LPPROCESS_INFORMATION)
+ lpProcessInformation: LPPROCESS_INFORMATION)
-> BOOL;
- pub fn WaitForSingleObject(hHandle: HANDLE,
- dwMilliseconds: DWORD)
- -> DWORD;
- pub fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint)
- -> BOOL;
- pub fn GetExitCodeProcess(hProcess: HANDLE,
- lpExitCode: LPDWORD)
- -> BOOL;
+ pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
+ pub fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL;
+ pub fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL;
pub fn GetSystemInfo(lpSystemInfo: LPSYSTEM_INFO);
pub fn VirtualAlloc(lpAddress: LPVOID,
dwSize: SIZE_T,
flAllocationType: DWORD,
flProtect: DWORD)
-> LPVOID;
- pub fn VirtualFree(lpAddress: LPVOID,
- dwSize: SIZE_T,
- dwFreeType: DWORD)
- -> BOOL;
+ pub fn VirtualFree(lpAddress: LPVOID, dwSize: SIZE_T, dwFreeType: DWORD) -> BOOL;
pub fn VirtualLock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL;
- pub fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T)
- -> BOOL;
+ pub fn VirtualUnlock(lpAddress: LPVOID, dwSize: SIZE_T) -> BOOL;
pub fn VirtualProtect(lpAddress: LPVOID,
dwSize: SIZE_T,
flNewProtect: DWORD,
pub fn UnmapViewOfFile(lpBaseAddress: LPCVOID) -> BOOL;
pub fn MoveFileExW(lpExistingFileName: LPCWSTR,
lpNewFileName: LPCWSTR,
- dwFlags: DWORD) -> BOOL;
+ dwFlags: DWORD)
+ -> BOOL;
pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
lpTargetFileName: LPCWSTR,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
- -> BOOL;
+ -> BOOL;
pub fn FlushFileBuffers(hFile: HANDLE) -> BOOL;
pub fn CreateFileW(lpFileName: LPCWSTR,
dwDesiredAccess: DWORD,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
dwCreationDisposition: DWORD,
dwFlagsAndAttributes: DWORD,
- hTemplateFile: HANDLE) -> HANDLE;
+ hTemplateFile: HANDLE)
+ -> HANDLE;
pub fn ReadFile(hFile: HANDLE,
lpBuffer: LPVOID,
nNumberOfBytesToRead: DWORD,
lpNumberOfBytesRead: LPDWORD,
- lpOverlapped: LPOVERLAPPED) -> BOOL;
+ lpOverlapped: LPOVERLAPPED)
+ -> BOOL;
pub fn WriteFile(hFile: HANDLE,
lpBuffer: LPVOID,
nNumberOfBytesToWrite: DWORD,
lpNumberOfBytesWritten: LPDWORD,
- lpOverlapped: LPOVERLAPPED) -> BOOL;
+ lpOverlapped: LPOVERLAPPED)
+ -> BOOL;
pub fn SetFilePointerEx(hFile: HANDLE,
liDistanceToMove: LARGE_INTEGER,
lpNewFilePointer: PLARGE_INTEGER,
- dwMoveMethod: DWORD) -> BOOL;
+ dwMoveMethod: DWORD)
+ -> BOOL;
pub fn SetEndOfFile(hFile: HANDLE) -> BOOL;
- pub fn GetSystemTimeAsFileTime(
- lpSystemTimeAsFileTime: LPFILETIME);
+ pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME);
- pub fn QueryPerformanceFrequency(
- lpFrequency: *mut LARGE_INTEGER) -> BOOL;
- pub fn QueryPerformanceCounter(
- lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL;
+ pub fn QueryPerformanceFrequency(lpFrequency: *mut LARGE_INTEGER) -> BOOL;
+ pub fn QueryPerformanceCounter(lpPerformanceCount: *mut LARGE_INTEGER) -> BOOL;
pub fn GetCurrentProcessId() -> DWORD;
- pub fn CreateNamedPipeW(
- lpName: LPCWSTR,
- dwOpenMode: DWORD,
- dwPipeMode: DWORD,
- nMaxInstances: DWORD,
- nOutBufferSize: DWORD,
- nInBufferSize: DWORD,
- nDefaultTimeOut: DWORD,
- lpSecurityAttributes: LPSECURITY_ATTRIBUTES
- ) -> HANDLE;
- pub fn ConnectNamedPipe(hNamedPipe: HANDLE,
- lpOverlapped: LPOVERLAPPED) -> BOOL;
- pub fn WaitNamedPipeW(lpNamedPipeName: LPCWSTR,
- nTimeOut: DWORD) -> BOOL;
+ pub fn CreateNamedPipeW(lpName: LPCWSTR,
+ dwOpenMode: DWORD,
+ dwPipeMode: DWORD,
+ nMaxInstances: DWORD,
+ nOutBufferSize: DWORD,
+ nInBufferSize: DWORD,
+ nDefaultTimeOut: DWORD,
+ lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
+ -> HANDLE;
+ pub fn ConnectNamedPipe(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED) -> BOOL;
+ pub fn WaitNamedPipeW(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD) -> BOOL;
pub fn SetNamedPipeHandleState(hNamedPipe: HANDLE,
lpMode: LPDWORD,
lpMaxCollectionCount: LPDWORD,
lpCollectDataTimeout: LPDWORD)
- -> BOOL;
+ -> BOOL;
pub fn CreateEventW(lpEventAttributes: LPSECURITY_ATTRIBUTES,
bManualReset: BOOL,
bInitialState: BOOL,
- lpName: LPCWSTR) -> HANDLE;
+ lpName: LPCWSTR)
+ -> HANDLE;
pub fn GetOverlappedResult(hFile: HANDLE,
lpOverlapped: LPOVERLAPPED,
lpNumberOfBytesTransferred: LPDWORD,
- bWait: BOOL) -> BOOL;
+ bWait: BOOL)
+ -> BOOL;
pub fn DisconnectNamedPipe(hNamedPipe: HANDLE) -> BOOL;
}
}
pub fn get_osfhandle(fd: c_int) -> c_long;
#[link_name = "_open_osfhandle"]
- pub fn open_osfhandle(osfhandle: intptr_t,
- flags: c_int) -> c_int;
+ pub fn open_osfhandle(osfhandle: intptr_t, flags: c_int) -> c_int;
}
}
}
}
-#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows
+#[test]
+fn work_on_windows() {
+} // FIXME #10872 needed for a happy windows
pub level: u32,
}
-pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO",
- "DEBUG"];
+pub const LOG_LEVEL_NAMES: [&'static str; 4] = ["ERROR", "WARN", "INFO", "DEBUG"];
/// Parse an individual log level that is either a number or a symbolic log level
fn parse_log_level(level: &str) -> Option<u32> {
- level.parse::<u32>().ok().or_else(|| {
- let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
- pos.map(|p| p as u32 + 1)
- }).map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
+ level.parse::<u32>()
+ .ok()
+ .or_else(|| {
+ let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
+ pos.map(|p| p as u32 + 1)
+ })
+ .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
}
/// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
let mods = parts.next();
let filter = parts.next();
if parts.next().is_some() {
- println!("warning: invalid logging spec '{}', \
- ignoring it (too many '/'s)", spec);
+ println!("warning: invalid logging spec '{}', ignoring it (too many '/'s)",
+ spec);
return (dirs, None);
}
- mods.map(|m| { for s in m.split(',') {
- if s.is_empty() { continue }
- let mut parts = s.split('=');
- let (log_level, name) = match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
- (Some(part0), None, None) => {
- // if the single argument is a log-level string or number,
- // treat that as a global fallback
- match parse_log_level(part0) {
- Some(num) => (num, None),
- None => (::MAX_LOG_LEVEL, Some(part0)),
- }
+ if let Some(m) = mods {
+ for s in m.split(',') {
+ if s.is_empty() {
+ continue
}
- (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
- (Some(part0), Some(part1), None) => {
- match parse_log_level(part1) {
- Some(num) => (num, Some(part0)),
- _ => {
- println!("warning: invalid logging spec '{}', \
- ignoring it", part1);
- continue
+ let mut parts = s.split('=');
+ let (log_level, name) = match (parts.next(),
+ parts.next().map(|s| s.trim()),
+ parts.next()) {
+ (Some(part0), None, None) => {
+ // if the single argument is a log-level string or number,
+ // treat that as a global fallback
+ match parse_log_level(part0) {
+ Some(num) => (num, None),
+ None => (::MAX_LOG_LEVEL, Some(part0)),
}
}
- },
- _ => {
- println!("warning: invalid logging spec '{}', \
- ignoring it", s);
- continue
- }
- };
- dirs.push(LogDirective {
- name: name.map(str::to_owned),
- level: log_level,
- });
- }});
+ (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
+ (Some(part0), Some(part1), None) => {
+ match parse_log_level(part1) {
+ Some(num) => (num, Some(part0)),
+ _ => {
+ println!("warning: invalid logging spec '{}', ignoring it", part1);
+ continue
+ }
+ }
+ }
+ _ => {
+ println!("warning: invalid logging spec '{}', ignoring it", s);
+ continue
+ }
+ };
+ dirs.push(LogDirective {
+ name: name.map(str::to_owned),
+ level: log_level,
+ });
+ }
+ }
(dirs, filter.map(str::to_owned))
}
fn log(&mut self, record: &LogRecord);
}
-struct DefaultLogger { handle: Stderr }
+struct DefaultLogger {
+ handle: Stderr,
+}
/// Wraps the log level with fmt implementations.
#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
let LogLevel(level) = *self;
match LOG_LEVEL_NAMES.get(level as usize - 1) {
Some(ref name) => fmt::Display::fmt(name, fmt),
- None => fmt::Display::fmt(&level, fmt)
+ None => fmt::Display::fmt(&level, fmt),
}
}
}
// Completely remove the local logger from TLS in case anyone attempts to
// frob the slot while we're doing the logging. This will destroy any logger
// set during logging.
- let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| {
- s.borrow_mut().take()
- }).unwrap_or_else(|| {
- box DefaultLogger { handle: io::stderr() }
- });
+ let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| s.borrow_mut().take())
+ .unwrap_or_else(|| {
+ box DefaultLogger { handle: io::stderr() }
+ });
logger.log(&LogRecord {
level: LogLevel(level),
args: args,
/// safely
#[doc(hidden)]
#[inline(always)]
-pub fn log_level() -> u32 { unsafe { LOG_LEVEL } }
+pub fn log_level() -> u32 {
+ unsafe { LOG_LEVEL }
+}
/// Replaces the thread-local logger with the specified logger, returning the old
/// logger.
pub fn set_logger(logger: Box<Logger + Send>) -> Option<Box<Logger + Send>> {
- let mut l = Some(logger);
- LOCAL_LOGGER.with(|slot| {
- mem::replace(&mut *slot.borrow_mut(), l.take())
- })
+ LOCAL_LOGGER.with(|slot| mem::replace(&mut *slot.borrow_mut(), Some(logger)))
}
/// A LogRecord is created by the logging macros, and passed as the only
/// argument to Loggers.
#[derive(Debug)]
pub struct LogRecord<'a> {
-
/// The module path of where the LogRecord originated.
pub module_path: &'a str,
// again to whether they should really be here or not. Hence, despite this
// check being expanded manually in the logging macro, this function checks
// the log level again.
- if level > unsafe { LOG_LEVEL } { return false }
+ if level > unsafe { LOG_LEVEL } {
+ return false
+ }
// This assertion should never get tripped unless we're in an at_exit
// handler after logging has been torn down and a logging attempt was made.
}
}
-fn enabled(level: u32,
- module: &str,
- iter: slice::Iter<directive::LogDirective>)
- -> bool {
+fn enabled(level: u32, module: &str, iter: slice::Iter<directive::LogDirective>) -> bool {
// Search for the longest match, the vector is assumed to be pre-sorted.
for directive in iter.rev() {
match directive.name {
- Some(ref name) if !module.starts_with(&name[..]) => {},
+ Some(ref name) if !module.starts_with(&name[..]) => {}
Some(..) | None => {
return level <= directive.level
}
#[test]
fn match_full_path() {
- let dirs = [
- LogDirective {
- name: Some("crate2".to_string()),
- level: 3
- },
- LogDirective {
- name: Some("crate1::mod1".to_string()),
- level: 2
- }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(2, "crate1::mod1", dirs.iter()));
assert!(!enabled(3, "crate1::mod1", dirs.iter()));
assert!(enabled(3, "crate2", dirs.iter()));
#[test]
fn no_match() {
- let dirs = [
- LogDirective { name: Some("crate2".to_string()), level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(!enabled(2, "crate3", dirs.iter()));
}
#[test]
fn match_beginning() {
- let dirs = [
- LogDirective { name: Some("crate2".to_string()), level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(3, "crate2::mod1", dirs.iter()));
}
#[test]
fn match_beginning_longest_match() {
- let dirs = [
- LogDirective { name: Some("crate2".to_string()), level: 3 },
- LogDirective { name: Some("crate2::mod".to_string()), level: 4 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: Some("crate2".to_string()),
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate2::mod".to_string()),
+ level: 4,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(4, "crate2::mod1", dirs.iter()));
assert!(!enabled(4, "crate2", dirs.iter()));
}
#[test]
fn match_default() {
- let dirs = [
- LogDirective { name: None, level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 2 }
- ];
+ let dirs = [LogDirective {
+ name: None,
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 2,
+ }];
assert!(enabled(2, "crate1::mod1", dirs.iter()));
assert!(enabled(3, "crate2::mod2", dirs.iter()));
}
#[test]
fn zero_level() {
- let dirs = [
- LogDirective { name: None, level: 3 },
- LogDirective { name: Some("crate1::mod1".to_string()), level: 0 }
- ];
+ let dirs = [LogDirective {
+ name: None,
+ level: 3,
+ },
+ LogDirective {
+ name: Some("crate1::mod1".to_string()),
+ level: 0,
+ }];
assert!(!enabled(1, "crate1::mod1", dirs.iter()));
assert!(enabled(3, "crate2::mod2", dirs.iter()));
}
/// Salsa20*](http://cr.yp.to/chacha.html)
#[derive(Copy, Clone)]
pub struct ChaChaRng {
- buffer: [u32; STATE_WORDS], // Internal buffer of output
- state: [u32; STATE_WORDS], // Initial state
- index: usize, // Index into state
+ buffer: [u32; STATE_WORDS], // Internal buffer of output
+ state: [u32; STATE_WORDS], // Initial state
+ index: usize, // Index into state
}
static EMPTY: ChaChaRng = ChaChaRng {
- buffer: [0; STATE_WORDS],
- state: [0; STATE_WORDS],
- index: STATE_WORDS
+ buffer: [0; STATE_WORDS],
+ state: [0; STATE_WORDS],
+ index: STATE_WORDS,
};
/// associated with a particular nonce can call this function with
/// arguments `0, desired_nonce`.
pub fn set_counter(&mut self, counter_low: u64, counter_high: u64) {
- self.state[12] = (counter_low >> 0) as u32;
+ self.state[12] = (counter_low >> 0) as u32;
self.state[13] = (counter_low >> 32) as u32;
- self.state[14] = (counter_high >> 0) as u32;
+ self.state[14] = (counter_high >> 0) as u32;
self.state[15] = (counter_high >> 32) as u32;
self.index = STATE_WORDS; // force recomputation
}
self.state[3] = 0x6B206574;
for i in 0..KEY_WORDS {
- self.state[4+i] = key[i];
+ self.state[4 + i] = key[i];
}
self.state[12] = 0;
self.index = 0;
// update 128-bit counter
self.state[12] += 1;
- if self.state[12] != 0 { return };
+ if self.state[12] != 0 {
+ return;
+ }
self.state[13] += 1;
- if self.state[13] != 0 { return };
+ if self.state[13] != 0 {
+ return;
+ }
self.state[14] += 1;
- if self.state[14] != 0 { return };
+ if self.state[14] != 0 {
+ return;
+ }
self.state[15] += 1;
}
}
// reset state
self.init(&[0; KEY_WORDS]);
// set key in place
- let key = &mut self.state[4 .. 4+KEY_WORDS];
+ let key = &mut self.state[4..4 + KEY_WORDS];
for (k, s) in key.iter_mut().zip(seed) {
*k = *s;
}
impl Rand for ChaChaRng {
fn rand<R: Rng>(other: &mut R) -> ChaChaRng {
- let mut key : [u32; KEY_WORDS] = [0; KEY_WORDS];
+ let mut key: [u32; KEY_WORDS] = [0; KEY_WORDS];
for word in &mut key {
*word = other.gen();
}
#[test]
fn test_rng_seeded() {
- let seed : &[_] = &[0,1,2,3,4,5,6,7];
+ let seed: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
let mut rb: ChaChaRng = SeedableRng::from_seed(seed);
assert!(order::equals(ra.gen_ascii_chars().take(100),
}
#[test]
+ #[rustfmt_skip]
fn test_rng_true_values() {
// Test vectors 1 and 2 from
// http://tools.ietf.org/html/draft-nir-cfrg-chacha20-poly1305-04
- let seed : &[_] = &[0; 8];
+ let seed: &[_] = &[0; 8];
let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
let v = (0..16).map(|_| ra.next_u32()).collect::<Vec<_>>();
0x281fed31, 0x45fb0a51, 0x1f0ae1ac, 0x6f4d794b));
- let seed : &[_] = &[0,1,2,3,4,5,6,7];
+ let seed: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
let mut ra: ChaChaRng = SeedableRng::from_seed(seed);
// Store the 17*i-th 32-bit word,
// i.e., the i-th word of the i-th 16-word block
- let mut v : Vec<u32> = Vec::new();
+ let mut v: Vec<u32> = Vec::new();
for _ in 0..16 {
v.push(ra.next_u32());
for _ in 0..16 {
#[test]
fn test_rng_clone() {
- let seed : &[_] = &[0; 8];
+ let seed: &[_] = &[0; 8];
let mut rng: ChaChaRng = SeedableRng::from_seed(seed);
let mut clone = rng.clone();
for _ in 0..16 {
// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
impl Rand for Exp1 {
#[inline]
- fn rand<R:Rng>(rng: &mut R) -> Exp1 {
+ fn rand<R: Rng>(rng: &mut R) -> Exp1 {
#[inline]
fn pdf(x: f64) -> f64 {
(-x).exp()
}
#[inline]
- fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
+ fn zero_case<R: Rng>(rng: &mut R, _u: f64) -> f64 {
ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
}
- Exp1(ziggurat(rng, false,
+ Exp1(ziggurat(rng,
+ false,
&ziggurat_tables::ZIG_EXP_X,
&ziggurat_tables::ZIG_EXP_F,
- pdf, zero_case))
+ pdf,
+ zero_case))
}
}
#[derive(Copy, Clone)]
pub struct Exp {
/// `lambda` stored as `1/lambda`, since this is what we scale by.
- lambda_inverse: f64
+ lambda_inverse: f64,
}
impl Exp {
}
impl Sample<f64> for Exp {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for Exp {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
#[cfg(test)]
mod tests {
- use std::prelude::v1::*;
-
use distributions::{Sample, IndependentSample};
use super::Exp;
mod bench {
extern crate test;
- use std::prelude::v1::*;
-
use self::test::Bencher;
use std::mem::size_of;
use super::Exp;
enum GammaRepr {
Large(GammaLargeShape),
One(Exp),
- Small(GammaSmallShape)
+ Small(GammaSmallShape),
}
// These two helpers could be made public, but saving the
/// shape parameters.
struct GammaSmallShape {
inv_shape: f64,
- large_shape: GammaLargeShape
+ large_shape: GammaLargeShape,
}
/// Gamma distribution where the shape parameter is larger than 1.
struct GammaLargeShape {
scale: f64,
c: f64,
- d: f64
+ d: f64,
}
impl Gamma {
assert!(scale > 0.0, "Gamma::new called with scale <= 0");
let repr = match shape {
- 1.0 => One(Exp::new(1.0 / scale)),
+ 1.0 => One(Exp::new(1.0 / scale)),
0.0 ... 1.0 => Small(GammaSmallShape::new_raw(shape, scale)),
- _ => Large(GammaLargeShape::new_raw(shape, scale))
+ _ => Large(GammaLargeShape::new_raw(shape, scale)),
};
Gamma { repr: repr }
}
fn new_raw(shape: f64, scale: f64) -> GammaSmallShape {
GammaSmallShape {
inv_shape: 1. / shape,
- large_shape: GammaLargeShape::new_raw(shape + 1.0, scale)
+ large_shape: GammaLargeShape::new_raw(shape + 1.0, scale),
}
}
}
GammaLargeShape {
scale: scale,
c: 1. / (9. * d).sqrt(),
- d: d
+ d: d,
}
}
}
impl Sample<f64> for Gamma {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl Sample<f64> for GammaSmallShape {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl Sample<f64> for GammaLargeShape {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for Gamma {
let StandardNormal(x) = rng.gen::<StandardNormal>();
let v_cbrt = 1.0 + self.c * x;
if v_cbrt <= 0.0 { // a^3 <= 0 iff a <= 0
- continue
+ continue;
}
let v = v_cbrt * v_cbrt * v_cbrt;
let x_sqr = x * x;
if u < 1.0 - 0.0331 * x_sqr * x_sqr ||
- u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
- return self.d * v * self.scale
+ u.ln() < 0.5 * x_sqr + self.d * (1.0 - v + v.ln()) {
+ return self.d * v * self.scale;
}
}
}
///
/// For `k > 0` integral, this distribution is the sum of the squares
/// of `k` independent standard normal random variables. For other
-/// `k`, this uses the equivalent characterisation `χ²(k) = Gamma(k/2,
+/// `k`, this uses the equivalent characterization `χ²(k) = Gamma(k/2,
/// 2)`.
pub struct ChiSquared {
repr: ChiSquaredRepr,
}
}
impl Sample<f64> for ChiSquared {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for ChiSquared {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
let StandardNormal(norm) = rng.gen::<StandardNormal>();
norm * norm
}
- DoFAnythingElse(ref g) => g.ind_sample(rng)
+ DoFAnythingElse(ref g) => g.ind_sample(rng),
}
}
}
FisherF {
numer: ChiSquared::new(m),
denom: ChiSquared::new(n),
- dof_ratio: n / m
+ dof_ratio: n / m,
}
}
}
impl Sample<f64> for FisherF {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for FisherF {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
/// freedom.
pub struct StudentT {
chi: ChiSquared,
- dof: f64
+ dof: f64,
}
impl StudentT {
assert!(n > 0.0, "StudentT::new called with `n <= 0`");
StudentT {
chi: ChiSquared::new(n),
- dof: n
+ dof: n,
}
}
}
impl Sample<f64> for StudentT {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for StudentT {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
#[cfg(test)]
mod tests {
- use std::prelude::v1::*;
-
use distributions::{Sample, IndependentSample};
use super::{ChiSquared, StudentT, FisherF};
#[cfg(test)]
mod bench {
extern crate test;
- use std::prelude::v1::*;
use self::test::Bencher;
use std::mem::size_of;
use distributions::IndependentSample;
/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
-pub struct RandSample<Sup> { _marker: PhantomData<Sup> }
+pub struct RandSample<Sup> {
+ _marker: PhantomData<Sup>,
+}
impl<Sup> RandSample<Sup> {
pub fn new() -> RandSample<Sup> {
}
impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup {
+ self.ind_sample(rng)
+ }
}
impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `usize`, so one can store references or indices into
/// another vector.
-pub struct WeightedChoice<'a, T:'a> {
+pub struct WeightedChoice<'a, T: 'a> {
items: &'a mut [Weighted<T>],
- weight_range: Range<usize>
+ weight_range: Range<usize>,
}
impl<'a, T: Clone> WeightedChoice<'a, T> {
/// - the total weight is larger than a `usize` can contain.
pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
// strictly speaking, this is subsumed by the total weight == 0 case
- assert!(!items.is_empty(), "WeightedChoice::new called with no items");
+ assert!(!items.is_empty(),
+ "WeightedChoice::new called with no items");
let mut running_total = 0_usize;
for item in &mut *items {
running_total = match running_total.checked_add(item.weight) {
Some(n) => n,
- None => panic!("WeightedChoice::new called with a total weight \
- larger than a usize can contain")
+ None => panic!("WeightedChoice::new called with a total weight larger than a \
+ usize can contain"),
};
item.weight = running_total;
}
- assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");
+ assert!(running_total != 0,
+ "WeightedChoice::new called with a total weight of 0");
WeightedChoice {
items: items,
// we're likely to be generating numbers in this range
// relatively often, so might as well cache it
- weight_range: Range::new(0, running_total)
+ weight_range: Range::new(0, running_total),
}
}
}
impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> T {
+ self.ind_sample(rng)
+ }
}
impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
-fn ziggurat<R: Rng, P, Z>(
- rng: &mut R,
- symmetric: bool,
- x_tab: ziggurat_tables::ZigTable,
- f_tab: ziggurat_tables::ZigTable,
- mut pdf: P,
- mut zero_case: Z)
- -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
+fn ziggurat<R: Rng, P, Z>(rng: &mut R,
+ symmetric: bool,
+ x_tab: ziggurat_tables::ZigTable,
+ f_tab: ziggurat_tables::ZigTable,
+ mut pdf: P,
+ mut zero_case: Z)
+ -> f64
+ where P: FnMut(f64) -> f64,
+ Z: FnMut(&mut R, f64) -> f64
+{
const SCALE: f64 = (1u64 << 53) as f64;
loop {
// reimplement the f64 generation as an optimisation suggested
// u is either U(-1, 1) or U(0, 1) depending on if this is a
// symmetric distribution or not.
- let u = if symmetric {2.0 * f - 1.0} else {f};
+ let u = if symmetric {
+ 2.0 * f - 1.0
+ } else {
+ f
+ };
let x = u * x_tab[i];
- let test_x = if symmetric { x.abs() } else {x};
+ let test_x = if symmetric {
+ x.abs()
+ } else {
+ x
+ };
// algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
if test_x < x_tab[i + 1] {
#[cfg(test)]
mod tests {
- use std::prelude::v1::*;
-
use {Rng, Rand};
use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};
}
// 0, 1, 2, 3, ...
- struct CountingRng { i: u32 }
+ struct CountingRng {
+ i: u32,
+ }
impl Rng for CountingRng {
fn next_u32(&mut self) -> u32 {
self.i += 1;
assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
}
#[test]
+ #[rustfmt_skip]
fn test_weighted_choice() {
// this makes assumptions about the internal implementation of
// WeightedChoice, specifically: it doesn't reorder the items,
}}
}
- t!(vec!(Weighted { weight: 1, item: 10}), [10]);
+ t!(vec!(Weighted { weight: 1, item: 10 }),
+ [10]);
// skip some
- t!(vec!(Weighted { weight: 0, item: 20},
- Weighted { weight: 2, item: 21},
- Weighted { weight: 0, item: 22},
- Weighted { weight: 1, item: 23}),
- [21,21, 23]);
+ t!(vec!(Weighted { weight: 0, item: 20 },
+ Weighted { weight: 2, item: 21 },
+ Weighted { weight: 0, item: 22 },
+ Weighted { weight: 1, item: 23 }),
+ [21, 21, 23]);
// different weights
- t!(vec!(Weighted { weight: 4, item: 30},
- Weighted { weight: 3, item: 31}),
- [30,30,30,30, 31,31,31]);
+ t!(vec!(Weighted { weight: 4, item: 30 },
+ Weighted { weight: 3, item: 31 }),
+ [30, 30, 30, 30, 31, 31, 31]);
// check that we're binary searching
// correctly with some vectors of odd
// length.
- t!(vec!(Weighted { weight: 1, item: 40},
- Weighted { weight: 1, item: 41},
- Weighted { weight: 1, item: 42},
- Weighted { weight: 1, item: 43},
- Weighted { weight: 1, item: 44}),
+ t!(vec!(Weighted { weight: 1, item: 40 },
+ Weighted { weight: 1, item: 41 },
+ Weighted { weight: 1, item: 42 },
+ Weighted { weight: 1, item: 43 },
+ Weighted { weight: 1, item: 44 }),
[40, 41, 42, 43, 44]);
- t!(vec!(Weighted { weight: 1, item: 50},
- Weighted { weight: 1, item: 51},
- Weighted { weight: 1, item: 52},
- Weighted { weight: 1, item: 53},
- Weighted { weight: 1, item: 54},
- Weighted { weight: 1, item: 55},
- Weighted { weight: 1, item: 56}),
+ t!(vec!(Weighted { weight: 1, item: 50 },
+ Weighted { weight: 1, item: 51 },
+ Weighted { weight: 1, item: 52 },
+ Weighted { weight: 1, item: 53 },
+ Weighted { weight: 1, item: 54 },
+ Weighted { weight: 1, item: 55 },
+ Weighted { weight: 1, item: 56 }),
[50, 51, 52, 53, 54, 55, 56]);
}
- #[test] #[should_panic]
+ #[test]
+ #[should_panic]
fn test_weighted_choice_no_items() {
WeightedChoice::<isize>::new(&mut []);
}
- #[test] #[should_panic]
+ #[test]
+ #[should_panic]
+ #[rustfmt_skip]
fn test_weighted_choice_zero_weight() {
- WeightedChoice::new(&mut [Weighted { weight: 0, item: 0},
- Weighted { weight: 0, item: 1}]);
+ WeightedChoice::new(&mut [Weighted { weight: 0, item: 0 },
+ Weighted { weight: 0, item: 1 }]);
}
- #[test] #[should_panic]
+ #[test]
+ #[should_panic]
+ #[rustfmt_skip]
fn test_weighted_choice_weight_overflows() {
let x = (!0) as usize / 2; // x + x + 2 is the overflow
WeightedChoice::new(&mut [Weighted { weight: x, item: 0 },
pub struct StandardNormal(pub f64);
impl Rand for StandardNormal {
- fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
+ fn rand<R: Rng>(rng: &mut R) -> StandardNormal {
#[inline]
fn pdf(x: f64) -> f64 {
- (-x*x/2.0).exp()
+ (-x * x / 2.0).exp()
}
#[inline]
- fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
+ fn zero_case<R: Rng>(rng: &mut R, u: f64) -> f64 {
// compute a random number in the tail by hand
// strange initial conditions, because the loop is not
y = y_.ln();
}
- if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
+ if u < 0.0 {
+ x - ziggurat_tables::ZIG_NORM_R
+ } else {
+ ziggurat_tables::ZIG_NORM_R - x
+ }
}
- StandardNormal(ziggurat(
- rng,
- true, // this is symmetric
- &ziggurat_tables::ZIG_NORM_X,
- &ziggurat_tables::ZIG_NORM_F,
- pdf, zero_case))
+ StandardNormal(ziggurat(rng,
+ true, // this is symmetric
+ &ziggurat_tables::ZIG_NORM_X,
+ &ziggurat_tables::ZIG_NORM_F,
+ pdf,
+ zero_case))
}
}
assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
Normal {
mean: mean,
- std_dev: std_dev
+ std_dev: std_dev,
}
}
}
impl Sample<f64> for Normal {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for Normal {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
/// std_dev**2)` distributed.
#[derive(Copy, Clone)]
pub struct LogNormal {
- norm: Normal
+ norm: Normal,
}
impl LogNormal {
}
}
impl Sample<f64> for LogNormal {
- fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 {
+ self.ind_sample(rng)
+ }
}
impl IndependentSample<f64> for LogNormal {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
#[cfg(test)]
mod tests {
- use std::prelude::v1::*;
-
use distributions::{Sample, IndependentSample};
use super::{Normal, LogNormal};
#[cfg(test)]
mod bench {
extern crate test;
- use std::prelude::v1::*;
use self::test::Bencher;
use std::mem::size_of;
- use distributions::{Sample};
+ use distributions::Sample;
use super::Normal;
#[bench]
pub struct Range<X> {
low: X,
range: X,
- accept_zone: X
+ accept_zone: X,
}
impl<X: SampleRange + PartialOrd> Range<X> {
impl<Sup: SampleRange> Sample<Sup> for Range<Sup> {
#[inline]
- fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
+ fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup {
+ self.ind_sample(rng)
+ }
}
impl<Sup: SampleRange> IndependentSample<Sup> for Range<Sup> {
fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
#[cfg(test)]
mod tests {
- use std::prelude::v1::*;
use distributions::{Sample, IndependentSample};
- use super::Range as Range;
+ use super::Range;
#[should_panic]
#[test]
)*
}}
}
- t!(i8, i16, i32, i64, isize,
- u8, u16, u32, u64, usize)
+ t!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize)
}
#[test]
pub type ZigTable = &'static [f64; 257];
pub const ZIG_NORM_R: f64 = 3.654152885361008796;
+#[rustfmt_skip]
pub static ZIG_NORM_X: [f64; 257] =
[3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074,
3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434,
0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746,
0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806,
0.000000000000000000];
+#[rustfmt_skip]
pub static ZIG_NORM_F: [f64; 257] =
[0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872,
0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100,
0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328,
1.000000000000000000];
pub const ZIG_EXP_R: f64 = 7.697117470131050077;
+#[rustfmt_skip]
pub static ZIG_EXP_X: [f64; 257] =
[8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696,
6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488,
0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842,
0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570,
0.000000000000000000];
+#[rustfmt_skip]
pub static ZIG_EXP_F: [f64; 257] =
[0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573,
0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797,
cnt: 0,
rsl: [w(0); RAND_SIZE_USIZE],
mem: [w(0); RAND_SIZE_USIZE],
- a: w(0), b: w(0), c: w(0),
+ a: w(0),
+ b: w(0),
+ c: w(0),
};
impl IsaacRng {
macro_rules! memloop {
($arr:expr) => {{
for i in (0..RAND_SIZE_USIZE).step_by(8) {
- a=a+$arr[i ]; b=b+$arr[i+1];
- c=c+$arr[i+2]; d=d+$arr[i+3];
- e=e+$arr[i+4]; f=f+$arr[i+5];
- g=g+$arr[i+6]; h=h+$arr[i+7];
+ a = a + $arr[i];
+ b = b + $arr[i + 1];
+ c = c + $arr[i + 2];
+ d = d + $arr[i + 3];
+ e = e + $arr[i + 4];
+ f = f + $arr[i + 5];
+ g = g + $arr[i + 6];
+ h = h + $arr[i + 7];
mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
+ self.mem[i] = a;
+ self.mem[i + 1] = b;
+ self.mem[i + 2] = c;
+ self.mem[i + 3] = d;
+ self.mem[i + 4] = e;
+ self.mem[i + 5] = f;
+ self.mem[i + 6] = g;
+ self.mem[i + 7] = h;
}
}}
}
} else {
for i in (0..RAND_SIZE_USIZE).step_by(8) {
mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
+ self.mem[i] = a;
+ self.mem[i + 1] = b;
+ self.mem[i + 2] = c;
+ self.mem[i + 3] = d;
+ self.mem[i + 4] = e;
+ self.mem[i + 5] = f;
+ self.mem[i + 6] = g;
+ self.mem[i + 7] = h;
}
}
cnt: 0,
rsl: [w(0); RAND_SIZE_64],
mem: [w(0); RAND_SIZE_64],
- a: w(0), b: w(0), c: w(0),
+ a: w(0),
+ b: w(0),
+ c: w(0),
};
impl Isaac64Rng {
let mut $var = w(0x9e3779b97f4a7c13);
)
}
- init!(a); init!(b); init!(c); init!(d);
- init!(e); init!(f); init!(g); init!(h);
+ init!(a);
+ init!(b);
+ init!(c);
+ init!(d);
+ init!(e);
+ init!(f);
+ init!(g);
+ init!(h);
macro_rules! mix {
() => {{
macro_rules! memloop {
($arr:expr) => {{
for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
- a=a+$arr[i ]; b=b+$arr[i+1];
- c=c+$arr[i+2]; d=d+$arr[i+3];
- e=e+$arr[i+4]; f=f+$arr[i+5];
- g=g+$arr[i+6]; h=h+$arr[i+7];
+ a = a + $arr[i];
+ b = b + $arr[i + 1];
+ c = c + $arr[i + 2];
+ d = d + $arr[i + 3];
+ e = e + $arr[i + 4];
+ f = f + $arr[i + 5];
+ g = g + $arr[i + 6];
+ h = h + $arr[i + 7];
mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
+ self.mem[i] = a;
+ self.mem[i + 1] = b;
+ self.mem[i + 2] = c;
+ self.mem[i + 3] = d;
+ self.mem[i + 4] = e;
+ self.mem[i + 5] = f;
+ self.mem[i + 6] = g;
+ self.mem[i + 7] = h;
}
}}
}
} else {
for i in (0..RAND_SIZE_64 / 8).map(|i| i * 8) {
mix!();
- self.mem[i ]=a; self.mem[i+1]=b;
- self.mem[i+2]=c; self.mem[i+3]=d;
- self.mem[i+4]=e; self.mem[i+5]=f;
- self.mem[i+6]=g; self.mem[i+7]=h;
+ self.mem[i] = a;
+ self.mem[i + 1] = b;
+ self.mem[i + 2] = c;
+ self.mem[i + 3] = d;
+ self.mem[i + 4] = e;
+ self.mem[i + 5] = f;
+ self.mem[i + 6] = g;
+ self.mem[i + 7] = h;
}
}
let mut a = self.a;
let mut b = self.b + self.c;
const MIDPOINT: usize = RAND_SIZE_64 / 2;
- const MP_VEC: [(usize, usize); 2] = [(0,MIDPOINT), (MIDPOINT, 0)];
+ const MP_VEC: [(usize, usize); 2] = [(0, MIDPOINT), (MIDPOINT, 0)];
macro_rules! ind {
($x:expr) => {
*self.mem.get_unchecked((($x >> 3).0 as usize) & (RAND_SIZE_64 - 1))
}
#[test]
+ #[rustfmt_skip]
fn test_rng_32_true_values() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
let seed: &[_] = &[12345, 67890, 54321, 9876];
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
- for _ in 0..10000 { rb.next_u32(); }
+ for _ in 0..10000 {
+ rb.next_u32();
+ }
let v = (0..10).map(|_| rb.next_u32()).collect::<Vec<_>>();
assert_eq!(v,
1576568959, 3507990155, 179069555, 141456972, 2478885421));
}
#[test]
+ #[rustfmt_skip]
fn test_rng_64_true_values() {
let seed: &[_] = &[1, 23, 456, 7890, 12345];
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
let seed: &[_] = &[12345, 67890, 54321, 9876];
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
// skip forward to the 10000th number
- for _ in 0..10000 { rb.next_u64(); }
+ for _ in 0..10000 {
+ rb.next_u64();
+ }
let v = (0..10).map(|_| rb.next_u64()).collect::<Vec<_>>();
assert_eq!(v,
17196852593171130876, 2606123525235546165, 15790932315217671084,
596345674630742204, 9947027391921273664, 11788097613744130851,
10391409374914919106));
+
}
#[test]
#![feature(num_bits_bytes)]
#![feature(staged_api)]
#![feature(step_by)]
+#![feature(custom_attribute)]
+#![allow(unused_attributes)]
-#![cfg_attr(test, feature(test, rand, rustc_private, iter_order))]
+#![cfg_attr(test, feature(test, rand, rustc_private, iter_order_deprecated))]
#![allow(deprecated)]
-#[cfg(test)] #[macro_use] extern crate std;
-#[cfg(test)] #[macro_use] extern crate log;
+#[cfg(test)]
+#[macro_use]
+extern crate std;
+#[cfg(test)]
+#[macro_use]
+extern crate log;
use core::f64;
use core::intrinsics;
/// Return an iterator that will yield an infinite number of randomly
/// generated items.
fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> {
- Generator { rng: self, _marker: PhantomData }
+ Generator {
+ rng: self,
+ _marker: PhantomData,
+ }
}
/// Generate a random value in the range [`low`, `high`).
/// Iterator which will generate a stream of random items.
///
/// This iterator is created via the `gen_iter` method on `Rng`.
-pub struct Generator<'a, T, R:'a> {
+pub struct Generator<'a, T, R: 'a> {
rng: &'a mut R,
- _marker: PhantomData<T>
+ _marker: PhantomData<T>,
}
impl<'a, T: Rand, R: Rng> Iterator for Generator<'a, T, R> {
/// Iterator which will continuously generate random ascii characters.
///
/// This iterator is created via the `gen_ascii_chars` method on `Rng`.
-pub struct AsciiGenerator<'a, R:'a> {
+pub struct AsciiGenerator<'a, R: 'a> {
rng: &'a mut R,
}
x: seed[0],
y: seed[1],
z: seed[2],
- w: seed[3]
+ w: seed[3],
}
}
}
tuple = rng.gen();
}
let (x, y, z, w) = tuple;
- XorShiftRng { x: x, y: y, z: z, w: w }
+ XorShiftRng {
+ x: x,
+ y: y,
+ z: z,
+ w: w,
+ }
}
}
mod test {
use std::__rand as rand;
- pub struct MyRng<R> { inner: R }
+ pub struct MyRng<R> {
+ inner: R,
+ }
impl<R: rand::Rng> ::Rng for MyRng<R> {
fn next_u32(&mut self) -> u32 {
use core::isize;
use core::usize;
-use {Rand,Rng};
+use {Rand, Rng};
impl Rand for isize {
#[inline]
impl Rand for () {
#[inline]
- fn rand<R: Rng>(_: &mut R) -> () { () }
+ fn rand<R: Rng>(_: &mut R) -> () {
+ ()
+ }
}
tuple_impl!{A}
tuple_impl!{A, B}
/// * `rng`: the random number generator to use.
/// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
/// * `reseeder`: the reseeding object to use.
- pub fn new(rng: R, generation_threshold: usize, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
+ pub fn new(rng: R, generation_threshold: usize, reseeder: Rsdr) -> ReseedingRng<R, Rsdr> {
ReseedingRng {
rng: rng,
generation_threshold: generation_threshold,
bytes_generated: 0,
- reseeder: reseeder
+ reseeder: reseeder,
}
}
rng: SeedableRng::from_seed(seed),
generation_threshold: DEFAULT_GENERATION_THRESHOLD,
bytes_generated: 0,
- reseeder: rsdr
+ reseeder: rsdr,
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Default for ReseedWithDefault {
#[stable(feature = "rust1", since = "1.0.0")]
- fn default() -> ReseedWithDefault { ReseedWithDefault }
+ fn default() -> ReseedWithDefault {
+ ReseedWithDefault
+ }
}
#[cfg(test)]
mod tests {
use std::prelude::v1::*;
- use core::iter::{order, repeat};
+ use core::iter::order;
use super::{ReseedingRng, ReseedWithDefault};
use {SeedableRng, Rng};
struct Counter {
- i: u32
+ i: u32,
}
impl Rng for Counter {
#[test]
fn test_reseeding() {
- let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
+ let mut rs = ReseedingRng::new(Counter { i: 0 }, 400, ReseedWithDefault);
let mut i = 0;
for _ in 0..1000 {
f(&d.data[d.start..d.end])
}
-
pub fn doc_as_u8(d: Doc) -> u8 {
assert_eq!(d.end, d.start + 1);
d.data[d.start]
}
- pub fn doc_as_u16(d: Doc) -> u16 {
- assert_eq!(d.end, d.start + 2);
- let mut b = [0; 2];
- bytes::copy_memory(&d.data[d.start..d.end], &mut b);
- unsafe { (*(b.as_ptr() as *const u16)).to_be() }
- }
-
- pub fn doc_as_u32(d: Doc) -> u32 {
- assert_eq!(d.end, d.start + 4);
- let mut b = [0; 4];
- bytes::copy_memory(&d.data[d.start..d.end], &mut b);
- unsafe { (*(b.as_ptr() as *const u32)).to_be() }
- }
-
pub fn doc_as_u64(d: Doc) -> u64 {
- assert_eq!(d.end, d.start + 8);
- let mut b = [0; 8];
- bytes::copy_memory(&d.data[d.start..d.end], &mut b);
- unsafe { (*(b.as_ptr() as *const u64)).to_be() }
+ if d.end >= 8 {
+ // For performance, we read 8 big-endian bytes,
+ // and mask off the junk if there is any. This
+ // obviously won't work on the first 8 bytes
+ // of a file - we will fall of the start
+ // of the page and segfault.
+
+ let mut b = [0; 8];
+ bytes::copy_memory(&d.data[d.end-8..d.end], &mut b);
+ let data = unsafe { (*(b.as_ptr() as *const u64)).to_be() };
+ let len = d.end - d.start;
+ if len < 8 {
+ data & ((1<<(len*8))-1)
+ } else {
+ data
+ }
+ } else {
+ let mut result = 0;
+ for b in &d.data[d.start..d.end] {
+ result = (result<<8) + (*b as u64);
+ }
+ result
+ }
}
- pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 }
- pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 }
- pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 }
- pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 }
+ #[inline] pub fn doc_as_u16(d: Doc) -> u16 { doc_as_u64(d) as u16 }
+ #[inline] pub fn doc_as_u32(d: Doc) -> u32 { doc_as_u64(d) as u32 }
+
+ #[inline] pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 }
+ #[inline] pub fn doc_as_i16(d: Doc) -> i16 { doc_as_u16(d) as i16 }
+ #[inline] pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 }
+ #[inline] pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 }
pub struct Decoder<'a> {
parent: Doc<'a>,
}
}
- fn write_vuint<W: Write>(w: &mut W, n: usize) -> EncodeResult {
+ pub fn write_vuint<W: Write>(w: &mut W, n: usize) -> EncodeResult {
if n < 0x7f { return write_sized_vuint(w, n, 1); }
if n < 0x4000 { return write_sized_vuint(w, n, 2); }
if n < 0x200000 { return write_sized_vuint(w, n, 3); }
}
}
- /// FIXME(pcwalton): Workaround for badness in trans. DO NOT USE ME.
- pub unsafe fn unsafe_clone(&self) -> Encoder<'a> {
- Encoder {
- writer: mem::transmute_copy(&self.writer),
- size_positions: self.size_positions.clone(),
- relax_limit: self.relax_limit,
- }
- }
-
pub fn start_tag(&mut self, tag_id: usize) -> EncodeResult {
debug!("Start tag {:?}", tag_id);
assert!(tag_id >= NUM_IMPLICIT_TAGS);
pub fn wr_tagged_u64(&mut self, tag_id: usize, v: u64) -> EncodeResult {
let bytes: [u8; 8] = unsafe { mem::transmute(v.to_be()) };
- self.wr_tagged_bytes(tag_id, &bytes)
+ // tagged integers are emitted in big-endian, with no
+ // leading zeros.
+ let leading_zero_bytes = v.leading_zeros()/8;
+ self.wr_tagged_bytes(tag_id, &bytes[leading_zero_bytes as usize..])
}
- pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult{
- let bytes: [u8; 4] = unsafe { mem::transmute(v.to_be()) };
- self.wr_tagged_bytes(tag_id, &bytes)
+ #[inline]
+ pub fn wr_tagged_u32(&mut self, tag_id: usize, v: u32) -> EncodeResult {
+ self.wr_tagged_u64(tag_id, v as u64)
}
+ #[inline]
pub fn wr_tagged_u16(&mut self, tag_id: usize, v: u16) -> EncodeResult {
- let bytes: [u8; 2] = unsafe { mem::transmute(v.to_be()) };
- self.wr_tagged_bytes(tag_id, &bytes)
+ self.wr_tagged_u64(tag_id, v as u64)
}
+ #[inline]
pub fn wr_tagged_u8(&mut self, tag_id: usize, v: u8) -> EncodeResult {
self.wr_tagged_bytes(tag_id, &[v])
}
+ #[inline]
pub fn wr_tagged_i64(&mut self, tag_id: usize, v: i64) -> EncodeResult {
self.wr_tagged_u64(tag_id, v as u64)
}
+ #[inline]
pub fn wr_tagged_i32(&mut self, tag_id: usize, v: i32) -> EncodeResult {
self.wr_tagged_u32(tag_id, v as u32)
}
+ #[inline]
pub fn wr_tagged_i16(&mut self, tag_id: usize, v: i16) -> EncodeResult {
self.wr_tagged_u16(tag_id, v as u16)
}
+ #[inline]
pub fn wr_tagged_i8(&mut self, tag_id: usize, v: i8) -> EncodeResult {
self.wr_tagged_bytes(tag_id, &[v as u8])
}
```
"##,
+// FIXME(#24111) Change the language here when const fn stabilizes
E0015: r##"
The only functions that can be called in static or constant expressions are
-`const` functions. Rust currently does not support more general compile-time
-function execution.
+`const` functions, and struct/enum constructors. `const` functions are only
+available on a nightly compiler. Rust currently does not support more general
+compile-time function execution.
+
+```
+const FOO: Option<u8> = Some(1); // enum constructor
+struct Bar {x: u8}
+const BAR: Bar = Bar {x: 1}; // struct constructor
+```
See [RFC 911] for more details on the design of `const fn`s.
contain references (with a maximum lifetime of `'a`).
[1]: https://github.com/rust-lang/rfcs/pull/1156
-"##
+"##,
+
+E0454: r##"
+A link name was given with an empty name. Erroneous code example:
+
+```
+#[link(name = "")] extern {} // error: #[link(name = "")] given with empty name
+```
+
+The rust compiler cannot link to an external library if you don't give it its
+name. Example:
+
+```
+#[link(name = "some_lib")] extern {} // ok!
+```
+"##,
+
+E0458: r##"
+An unknown "kind" was specified for a link attribute. Erroneous code example:
+
+```
+#[link(kind = "wonderful_unicorn")] extern {}
+// error: unknown kind: `wonderful_unicorn`
+```
+
+Please specify a valid "kind" value, from one of the following:
+ * static
+ * dylib
+ * framework
+"##,
+
+E0459: r##"
+A link was used without a name parameter. Erroneous code example:
+
+```
+#[link(kind = "dylib")] extern {}
+// error: #[link(...)] specified without `name = "foo"`
+```
+
+Please add the name parameter to allow the rust compiler to find the library
+you want. Example:
+
+```
+#[link(kind = "dylib", name = "some_lib")] extern {} // ok!
+```
+"##,
+
+E0493: r##"
+A type with a destructor was assigned to an invalid type of variable. Erroneous
+code example:
+
+```
+struct Foo {
+ a: u32
+}
+
+impl Drop for Foo {
+ fn drop(&mut self) {}
+}
+
+const F : Foo = Foo { a : 0 };
+// error: constants are not allowed to have destructors
+static S : Foo = Foo { a : 0 };
+// error: statics are not allowed to have destructors
+```
+
+To solve this issue, please use a type which does allow the usage of type with
+destructors.
+"##,
+
+E0494: r##"
+A reference of an interior static was assigned to another const/static.
+Erroneous code example:
+
+```
+struct Foo {
+ a: u32
+}
+
+static S : Foo = Foo { a : 0 };
+static A : &'static u32 = &S.a;
+// error: cannot refer to the interior of another static, use a
+// constant instead
+```
+
+The "base" variable has to be a const if you want another static/const variable
+to refer to one of its fields. Example:
+
+```
+struct Foo {
+ a: u32
+}
+
+const S : Foo = Foo { a : 0 };
+static A : &'static u32 = &S.a; // ok!
+```
+"##,
+
+E0496: r##"
+A lifetime name is shadowing another lifetime name. Erroneous code example:
+
+```
+struct Foo<'a> {
+ a: &'a i32,
+}
+
+impl<'a> Foo<'a> {
+ fn f<'a>(x: &'a i32) { // error: lifetime name `'a` shadows a lifetime
+ // name that is already in scope
+ }
+}
+```
+
+Please change the name of one of the lifetimes to remove this error. Example:
+
+
+```
+struct Foo<'a> {
+ a: &'a i32,
+}
+
+impl<'a> Foo<'a> {
+ fn f<'b>(x: &'b i32) { // ok!
+ }
+}
+
+fn main() {
+}
+```
+"##,
+
+E0497: r##"
+A stability attribute was used outside of the standard library. Erroneous code
+example:
+
+```
+#[stable] // error: stability attributes may not be used outside of the
+ // standard library
+fn foo() {}
+```
+
+It is not possible to use stability attributes outside of the standard library.
+Also, for now, it is not possible to write deprecation messages either.
+"##,
}
E0314, // closure outlives stack frame
E0315, // cannot invoke closure outside of its lifetime
E0316, // nested quantification of lifetimes
- E0400 // overloaded derefs are not allowed in constants
+ E0400, // overloaded derefs are not allowed in constants
+ E0452, // malformed lint attribute
+ E0453, // overruled by outer forbid
+ E0455, // native frameworks are only available on OSX targets
+ E0456, // plugin `..` is not available for triple `..`
+ E0457, // plugin `..` only found in rlib format, but must be available...
+ E0460, // found possibly newer version of crate `..`
+ E0461, // couldn't find crate `..` with expected target triple ..
+ E0462, // found staticlib `..` instead of rlib or dylib
+ E0463, // can't find crate for `..`
+ E0464, // multiple matching crates for `..`
+ E0465, // multiple .. candidates for `..` found
+ E0466, // bad macro import
+ E0467, // bad macro reexport
+ E0468, // an `extern crate` loading macros must be at the crate root
+ E0469, // imported macro not found
+ E0470, // reexported macro not found
+ E0471, // constant evaluation error: ..
+ E0472, // asm! is unsupported on this target
+ E0473, // dereference of reference outside its lifetime
+ E0474, // captured variable `..` does not outlive the enclosing closure
+ E0475, // index of slice outside its lifetime
+ E0476, // lifetime of the source pointer does not outlive lifetime bound...
+ E0477, // the type `..` does not fulfill the required lifetime...
+ E0478, // lifetime bound not satisfied
+ E0479, // the type `..` (provided as the value of a type parameter) is...
+ E0480, // lifetime of method receiver does not outlive the method call
+ E0481, // lifetime of function argument does not outlive the function call
+ E0482, // lifetime of return value does not outlive the function call
+ E0483, // lifetime of operand does not outlive the operation
+ E0484, // reference is not valid at the time of borrow
+ E0485, // automatically reference is not valid at the time of borrow
+ E0486, // type of expression contains references that are not valid during...
+ E0487, // unsafe use of destructor: destructor might be called while...
+ E0488, // lifetime of variable does not enclose its declaration
+ E0489, // type/lifetime parameter not in scope here
+ E0490, // a value of type `..` is borrowed for too long
+ E0491, // in type `..`, reference has a longer lifetime than the data it...
+ E0492, // cannot borrow a constant which contains interior mutability
+ E0495, // cannot infer an appropriate lifetime due to conflicting requirements
+ E0498, // malformed plugin attribute
+ E0514, // metadata version mismatch
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use session::Session;
+
+use syntax::ast;
+use syntax::attr::AttrMetaMethods;
+use syntax::visit;
+use syntax::visit::Visitor;
+
+#[derive(Copy, Clone, PartialEq)]
+enum Target {
+ Fn,
+ Struct,
+ Enum,
+ Other,
+}
+
+impl Target {
+ fn from_item(item: &ast::Item) -> Target {
+ match item.node {
+ ast::ItemFn(..) => Target::Fn,
+ ast::ItemStruct(..) => Target::Struct,
+ ast::ItemEnum(..) => Target::Enum,
+ _ => Target::Other,
+ }
+ }
+}
+
+struct CheckAttrVisitor<'a> {
+ sess: &'a Session,
+}
+
+impl<'a> CheckAttrVisitor<'a> {
+ fn check_inline(&self, attr: &ast::Attribute, target: Target) {
+ if target != Target::Fn {
+ self.sess.span_err(
+ attr.span,
+ "attribute should be applied to function");
+ }
+ }
+
+ fn check_repr(&self, attr: &ast::Attribute, target: Target) {
+ let words = match attr.meta_item_list() {
+ Some(words) => words,
+ None => {
+ return;
+ }
+ };
+ for word in words {
+ let word: &str = &word.name();
+ match word {
+ "C" => {
+ if target != Target::Struct && target != Target::Enum {
+ self.sess.span_err(
+ attr.span,
+ "attribute should be applied to struct or enum");
+ }
+ }
+ "packed" |
+ "simd" => {
+ if target != Target::Struct {
+ self.sess.span_err(
+ attr.span,
+ "attribute should be applied to struct");
+ }
+ }
+ "i8" | "u8" | "i16" | "u16" |
+ "i32" | "u32" | "i64" | "u64" |
+ "isize" | "usize" => {
+ if target != Target::Enum {
+ self.sess.span_err(
+ attr.span,
+ "attribute should be applied to enum");
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ fn check_attribute(&self, attr: &ast::Attribute, target: Target) {
+ let name: &str = &attr.name();
+ match name {
+ "inline" => self.check_inline(attr, target),
+ "repr" => self.check_repr(attr, target),
+ _ => (),
+ }
+ }
+}
+
+impl<'a, 'v> Visitor<'v> for CheckAttrVisitor<'a> {
+ fn visit_item(&mut self, item: &ast::Item) {
+ let target = Target::from_item(item);
+ for attr in &item.attrs {
+ self.check_attribute(attr, target);
+ }
+ }
+}
+
+pub fn check_crate(sess: &Session, krate: &ast::Crate) {
+ visit::walk_crate(&mut CheckAttrVisitor { sess: sess }, krate);
+}
use front::map::{self, Node};
use syntax::abi;
use rustc_front::hir::{Block, FnDecl};
-use syntax::ast::{NodeId, Ident};
+use syntax::ast::{Name, NodeId};
use rustc_front::hir as ast;
use syntax::codemap::Span;
use rustc_front::visit::FnKind;
/// These are all the components one can extract from a fn item for
/// use when implementing FnLikeNode operations.
struct ItemFnParts<'a> {
- ident: Ident,
+ name: Name,
decl: &'a ast::FnDecl,
unsafety: ast::Unsafety,
constness: ast::Constness,
pub fn kind(self) -> FnKind<'a> {
let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
- FnKind::ItemFn(p.ident, p.generics, p.unsafety, p.constness, p.abi, p.vis)
+ FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis)
};
let closure = |_: ClosureParts| {
FnKind::Closure
};
- let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| {
- FnKind::Method(ident, sig, vis)
+ let method = |_, name: Name, sig: &'a ast::MethodSig, vis, _, _| {
+ FnKind::Method(name, sig, vis)
};
self.handle(item, method, closure)
}
fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
I: FnOnce(ItemFnParts<'a>) -> A,
M: FnOnce(NodeId,
- Ident,
+ Name,
&'a ast::MethodSig,
Option<ast::Visibility>,
&'a ast::Block,
ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) =>
item_fn(ItemFnParts {
id: i.id,
- ident: i.ident,
+ name: i.name,
decl: &**decl,
unsafety: unsafety,
body: &**block,
},
map::NodeTraitItem(ti) => match ti.node {
ast::MethodTraitItem(ref sig, Some(ref body)) => {
- method(ti.id, ti.ident, sig, None, body, ti.span)
+ method(ti.id, ti.name, sig, None, body, ti.span)
}
_ => panic!("trait method FnLikeNode that is not fn-like"),
},
map::NodeImplItem(ii) => {
match ii.node {
ast::MethodImplItem(ref sig, ref body) => {
- method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
+ method(ii.id, ii.name, sig, Some(ii.vis), body, ii.span)
}
_ => {
panic!("impl method FnLikeNode that is not fn-like")
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+use super::MapEntry::*;
+
+use rustc_front::hir::*;
+use rustc_front::util;
+use rustc_front::visit::{self, Visitor};
+use middle::def_id::{CRATE_DEF_INDEX, DefIndex};
+use std::iter::repeat;
+use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
+use syntax::codemap::Span;
+
+/// A Visitor that walks over an AST and collects Node's into an AST
+/// Map.
+pub struct NodeCollector<'ast> {
+ pub map: Vec<MapEntry<'ast>>,
+ pub definitions: Definitions,
+ pub parent_node: NodeId,
+}
+
+impl<'ast> NodeCollector<'ast> {
+ pub fn root() -> NodeCollector<'ast> {
+ let mut collector = NodeCollector {
+ map: vec![],
+ definitions: Definitions::new(),
+ parent_node: CRATE_NODE_ID,
+ };
+ collector.insert_entry(CRATE_NODE_ID, RootCrate);
+
+ let result = collector.create_def_with_parent(None, CRATE_NODE_ID, DefPathData::CrateRoot);
+ assert_eq!(result, CRATE_DEF_INDEX);
+
+ collector.create_def_with_parent(Some(CRATE_DEF_INDEX), DUMMY_NODE_ID, DefPathData::Misc);
+
+ collector
+ }
+
+ pub fn extend(parent: &'ast InlinedParent,
+ parent_node: NodeId,
+ parent_def_path: DefPath,
+ map: Vec<MapEntry<'ast>>,
+ definitions: Definitions)
+ -> NodeCollector<'ast> {
+ let mut collector = NodeCollector {
+ map: map,
+ parent_node: parent_node,
+ definitions: definitions,
+ };
+
+ collector.insert_entry(parent_node, RootInlinedParent(parent));
+ collector.create_def(parent_node, DefPathData::InlinedRoot(parent_def_path));
+
+ collector
+ }
+
+ fn parent_def(&self) -> Option<DefIndex> {
+ let mut parent_node = Some(self.parent_node);
+ while let Some(p) = parent_node {
+ if let Some(q) = self.definitions.opt_def_index(p) {
+ return Some(q);
+ }
+ parent_node = self.map[p as usize].parent_node();
+ }
+ None
+ }
+
+ fn create_def(&mut self, node_id: NodeId, data: DefPathData) -> DefIndex {
+ let parent_def = self.parent_def();
+ self.definitions.create_def_with_parent(parent_def, node_id, data)
+ }
+
+ fn create_def_with_parent(&mut self,
+ parent: Option<DefIndex>,
+ node_id: NodeId,
+ data: DefPathData)
+ -> DefIndex {
+ self.definitions.create_def_with_parent(parent, node_id, data)
+ }
+
+ fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
+ debug!("ast_map: {:?} => {:?}", id, entry);
+ let len = self.map.len();
+ if id as usize >= len {
+ self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
+ }
+ self.map[id as usize] = entry;
+ }
+
+ fn insert_def(&mut self, id: NodeId, node: Node<'ast>, data: DefPathData) -> DefIndex {
+ self.insert(id, node);
+ self.create_def(id, data)
+ }
+
+ fn insert(&mut self, id: NodeId, node: Node<'ast>) {
+ let entry = MapEntry::from_node(self.parent_node, node);
+ self.insert_entry(id, entry);
+ }
+}
+
+impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
+ fn visit_item(&mut self, i: &'ast Item) {
+ // Pick the def data. This need not be unique, but the more
+ // information we encapsulate into
+ let def_data = match i.node {
+ ItemDefaultImpl(..) | ItemImpl(..) => DefPathData::Impl,
+ ItemEnum(..) | ItemStruct(..) | ItemTrait(..) => DefPathData::Type(i.name),
+ ItemExternCrate(..) | ItemMod(..) => DefPathData::Mod(i.name),
+ ItemStatic(..) | ItemConst(..) | ItemFn(..) => DefPathData::Value(i.name),
+ _ => DefPathData::Misc,
+ };
+
+ self.insert_def(i.id, NodeItem(i), def_data);
+
+ let parent_node = self.parent_node;
+ self.parent_node = i.id;
+
+ match i.node {
+ ItemImpl(..) => {}
+ ItemEnum(ref enum_definition, _) => {
+ for v in &enum_definition.variants {
+ let variant_def_index =
+ self.insert_def(v.node.data.id(),
+ NodeVariant(&**v),
+ DefPathData::EnumVariant(v.node.name));
+
+ for field in v.node.data.fields() {
+ self.create_def_with_parent(
+ Some(variant_def_index),
+ field.node.id,
+ DefPathData::Field(field.node.kind));
+ }
+ }
+ }
+ ItemForeignMod(..) => {
+ }
+ ItemStruct(ref struct_def, _) => {
+ // If this is a tuple-like struct, register the constructor.
+ if !struct_def.is_struct() {
+ self.insert_def(struct_def.id(),
+ NodeStructCtor(struct_def),
+ DefPathData::StructCtor);
+ }
+
+ for field in struct_def.fields() {
+ self.create_def(field.node.id, DefPathData::Field(field.node.kind));
+ }
+ }
+ ItemTrait(_, _, ref bounds, _) => {
+ for b in bounds.iter() {
+ if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
+ self.insert(t.trait_ref.ref_id, NodeItem(i));
+ }
+ }
+ }
+ ItemUse(ref view_path) => {
+ match view_path.node {
+ ViewPathList(_, ref paths) => {
+ for path in paths {
+ self.insert(path.node.id(), NodeItem(i));
+ }
+ }
+ _ => ()
+ }
+ }
+ _ => {}
+ }
+ visit::walk_item(self, i);
+ self.parent_node = parent_node;
+ }
+
+ fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
+ self.insert_def(foreign_item.id,
+ NodeForeignItem(foreign_item),
+ DefPathData::Value(foreign_item.name));
+
+ let parent_node = self.parent_node;
+ self.parent_node = foreign_item.id;
+ visit::walk_foreign_item(self, foreign_item);
+ self.parent_node = parent_node;
+ }
+
+ fn visit_generics(&mut self, generics: &'ast Generics) {
+ for ty_param in generics.ty_params.iter() {
+ self.insert_def(ty_param.id,
+ NodeTyParam(ty_param),
+ DefPathData::TypeParam(ty_param.name));
+ }
+
+ visit::walk_generics(self, generics);
+ }
+
+ fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
+ let def_data = match ti.node {
+ MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::Value(ti.name),
+ TypeTraitItem(..) => DefPathData::Type(ti.name),
+ };
+
+ self.insert(ti.id, NodeTraitItem(ti));
+ self.create_def(ti.id, def_data);
+
+ let parent_node = self.parent_node;
+ self.parent_node = ti.id;
+
+ match ti.node {
+ ConstTraitItem(_, Some(ref expr)) => {
+ self.create_def(expr.id, DefPathData::Initializer);
+ }
+ _ => { }
+ }
+
+ visit::walk_trait_item(self, ti);
+
+ self.parent_node = parent_node;
+ }
+
+ fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
+ let def_data = match ii.node {
+ MethodImplItem(..) | ConstImplItem(..) => DefPathData::Value(ii.name),
+ TypeImplItem(..) => DefPathData::Type(ii.name),
+ };
+
+ self.insert_def(ii.id, NodeImplItem(ii), def_data);
+
+ let parent_node = self.parent_node;
+ self.parent_node = ii.id;
+
+ match ii.node {
+ ConstImplItem(_, ref expr) => {
+ self.create_def(expr.id, DefPathData::Initializer);
+ }
+ _ => { }
+ }
+
+ visit::walk_impl_item(self, ii);
+
+ self.parent_node = parent_node;
+ }
+
+ fn visit_pat(&mut self, pat: &'ast Pat) {
+ let maybe_binding = match pat.node {
+ PatIdent(_, id, _) => Some(id.node),
+ _ => None
+ };
+
+ if let Some(id) = maybe_binding {
+ self.insert_def(pat.id, NodeLocal(pat), DefPathData::Binding(id.name));
+ } else {
+ self.insert(pat.id, NodePat(pat));
+ }
+
+ let parent_node = self.parent_node;
+ self.parent_node = pat.id;
+ visit::walk_pat(self, pat);
+ self.parent_node = parent_node;
+ }
+
+ fn visit_expr(&mut self, expr: &'ast Expr) {
+ self.insert(expr.id, NodeExpr(expr));
+
+ match expr.node {
+ ExprClosure(..) => { self.create_def(expr.id, DefPathData::ClosureExpr); }
+ _ => { }
+ }
+
+ let parent_node = self.parent_node;
+ self.parent_node = expr.id;
+ visit::walk_expr(self, expr);
+ self.parent_node = parent_node;
+ }
+
+ fn visit_stmt(&mut self, stmt: &'ast Stmt) {
+ let id = util::stmt_id(stmt);
+ self.insert(id, NodeStmt(stmt));
+ let parent_node = self.parent_node;
+ self.parent_node = id;
+ visit::walk_stmt(self, stmt);
+ self.parent_node = parent_node;
+ }
+
+ fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
+ b: &'ast Block, s: Span, id: NodeId) {
+ assert_eq!(self.parent_node, id);
+ visit::walk_fn(self, fk, fd, b, s);
+ }
+
+ fn visit_block(&mut self, block: &'ast Block) {
+ self.insert(block.id, NodeBlock(block));
+ let parent_node = self.parent_node;
+ self.parent_node = block.id;
+ visit::walk_block(self, block);
+ self.parent_node = parent_node;
+ }
+
+ fn visit_lifetime(&mut self, lifetime: &'ast Lifetime) {
+ self.insert(lifetime.id, NodeLifetime(lifetime));
+ }
+
+ fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
+ self.create_def(def.lifetime.id, DefPathData::LifetimeDef(def.lifetime.name));
+ self.visit_lifetime(&def.lifetime);
+ }
+
+ fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) {
+ self.create_def(macro_def.id, DefPathData::MacroDef(macro_def.name));
+ }
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::{DefId, DefIndex};
+use rustc_data_structures::fnv::FnvHashMap;
+use rustc_front::hir;
+use syntax::ast;
+use syntax::parse::token::InternedString;
+use util::nodemap::NodeMap;
+
+#[derive(Clone)]
+pub struct Definitions {
+ data: Vec<DefData>,
+ key_map: FnvHashMap<DefKey, DefIndex>,
+ node_map: NodeMap<DefIndex>,
+}
+
+/// A unique identifier that we can use to lookup a definition
+/// precisely. It combines the index of the definition's parent (if
+/// any) with a `DisambiguatedDefPathData`.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct DefKey {
+ /// Parent path.
+ pub parent: Option<DefIndex>,
+
+ /// Identifier of this node.
+ pub disambiguated_data: DisambiguatedDefPathData,
+}
+
+/// Pair of `DefPathData` and an integer disambiguator. The integer is
+/// normally 0, but in the event that there are multiple defs with the
+/// same `parent` and `data`, we use this field to disambiguate
+/// between them. This introduces some artificial ordering dependency
+/// but means that if you have (e.g.) two impls for the same type in
+/// the same module, they do get distinct def-ids.
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub struct DisambiguatedDefPathData {
+ pub data: DefPathData,
+ pub disambiguator: u32
+}
+
+/// For each definition, we track the following data. A definition
+/// here is defined somewhat circularly as "something with a def-id",
+/// but it generally corresponds to things like structs, enums, etc.
+/// There are also some rather random cases (like const initializer
+/// expressions) that are mostly just leftovers.
+#[derive(Clone, Debug)]
+pub struct DefData {
+ pub key: DefKey,
+
+ /// Local ID within the HIR.
+ pub node_id: ast::NodeId,
+}
+
+pub type DefPath = Vec<DisambiguatedDefPathData>;
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+pub enum DefPathData {
+ // Root: these should only be used for the root nodes, because
+ // they are treated specially by the `def_path` function.
+ CrateRoot,
+ InlinedRoot(DefPath),
+
+ // Catch-all for random DefId things like DUMMY_NODE_ID
+ Misc,
+
+ // Different kinds of items and item-like things:
+ Impl,
+ Type(ast::Name),
+ Mod(ast::Name),
+ Value(ast::Name),
+ MacroDef(ast::Name),
+ ClosureExpr,
+
+ // Subportions of items
+ TypeParam(ast::Name),
+ LifetimeDef(ast::Name),
+ EnumVariant(ast::Name),
+ PositionalField,
+ Field(hir::StructFieldKind),
+ StructCtor, // implicit ctor for a tuple-like struct
+ Initializer, // initializer for a const
+ Binding(ast::Name), // pattern binding
+
+ // An external crate that does not have an `extern crate` in this
+ // crate.
+ DetachedCrate(ast::Name),
+}
+
+impl Definitions {
+ pub fn new() -> Definitions {
+ Definitions {
+ data: vec![],
+ key_map: FnvHashMap(),
+ node_map: NodeMap(),
+ }
+ }
+
+ pub fn len(&self) -> usize {
+ self.data.len()
+ }
+
+ pub fn def_key(&self, index: DefIndex) -> DefKey {
+ self.data[index.as_usize()].key.clone()
+ }
+
+ /// Returns the path from the crate root to `index`. The root
+ /// nodes are not included in the path (i.e., this will be an
+ /// empty vector for the crate root). For an inlined item, this
+ /// will be the path of the item in the external crate (but the
+ /// path will begin with the path to the external crate).
+ pub fn def_path(&self, index: DefIndex) -> DefPath {
+ make_def_path(index, |p| self.def_key(p))
+ }
+
+ pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> {
+ self.node_map.get(&node).cloned()
+ }
+
+ pub fn opt_local_def_id(&self, node: ast::NodeId) -> Option<DefId> {
+ self.opt_def_index(node).map(DefId::local)
+ }
+
+ pub fn as_local_node_id(&self, def_id: DefId) -> Option<ast::NodeId> {
+ if def_id.krate == LOCAL_CRATE {
+ assert!(def_id.index.as_usize() < self.data.len());
+ Some(self.data[def_id.index.as_usize()].node_id)
+ } else {
+ None
+ }
+ }
+
+ pub fn create_def_with_parent(&mut self,
+ parent: Option<DefIndex>,
+ node_id: ast::NodeId,
+ data: DefPathData)
+ -> DefIndex {
+ assert!(!self.node_map.contains_key(&node_id),
+ "adding a def'n for node-id {:?} and data {:?} but a previous def'n exists: {:?}",
+ node_id,
+ data,
+ self.data[self.node_map[&node_id].as_usize()]);
+
+ // Find a unique DefKey. This basically means incrementing the disambiguator
+ // until we get no match.
+ let mut key = DefKey {
+ parent: parent,
+ disambiguated_data: DisambiguatedDefPathData {
+ data: data,
+ disambiguator: 0
+ }
+ };
+
+ while self.key_map.contains_key(&key) {
+ key.disambiguated_data.disambiguator += 1;
+ }
+
+ // Create the definition.
+ let index = DefIndex::new(self.data.len());
+ self.data.push(DefData { key: key.clone(), node_id: node_id });
+ self.node_map.insert(node_id, index);
+ self.key_map.insert(key, index);
+
+ index
+ }
+}
+
+impl DefPathData {
+ pub fn as_interned_str(&self) -> InternedString {
+ use self::DefPathData::*;
+ match *self {
+ Type(name) |
+ Mod(name) |
+ Value(name) |
+ MacroDef(name) |
+ TypeParam(name) |
+ LifetimeDef(name) |
+ EnumVariant(name) |
+ DetachedCrate(name) |
+ Binding(name) => {
+ name.as_str()
+ }
+
+ Field(hir::StructFieldKind::NamedField(name, _)) => {
+ name.as_str()
+ }
+
+ PositionalField |
+ Field(hir::StructFieldKind::UnnamedField(_)) => {
+ InternedString::new("<field>")
+ }
+
+ // note that this does not show up in user printouts
+ CrateRoot => {
+ InternedString::new("<root>")
+ }
+
+ // note that this does not show up in user printouts
+ InlinedRoot(_) => {
+ InternedString::new("<inlined-root>")
+ }
+
+ Misc => {
+ InternedString::new("?")
+ }
+
+ Impl => {
+ InternedString::new("<impl>")
+ }
+
+ ClosureExpr => {
+ InternedString::new("<closure>")
+ }
+
+ StructCtor => {
+ InternedString::new("<constructor>")
+ }
+
+ Initializer => {
+ InternedString::new("<initializer>")
+ }
+ }
+ }
+
+ pub fn to_string(&self) -> String {
+ self.as_interned_str().to_string()
+ }
+}
+
+pub fn make_def_path<FN>(start_index: DefIndex, mut get_key: FN) -> DefPath
+ where FN: FnMut(DefIndex) -> DefKey
+{
+ let mut result = vec![];
+ let mut index = Some(start_index);
+ while let Some(p) = index {
+ let key = get_key(p);
+ match key.disambiguated_data.data {
+ DefPathData::CrateRoot => {
+ assert!(key.parent.is_none());
+ break;
+ }
+ DefPathData::InlinedRoot(ref p) => {
+ assert!(key.parent.is_none());
+ result.extend(p.iter().cloned().rev());
+ break;
+ }
+ _ => {
+ result.push(key.disambiguated_data);
+ index = key.parent;
+ }
+ }
+ }
+ result.reverse();
+ result
+}
pub use self::Node::*;
pub use self::PathElem::*;
use self::MapEntry::*;
+use self::collector::NodeCollector;
+pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
use metadata::inline::InlinedItem;
use metadata::inline::InlinedItem as II;
use middle::def_id::DefId;
use syntax::abi;
-use syntax::ast::{Name, NodeId, Ident, CRATE_NODE_ID, DUMMY_NODE_ID};
+use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID};
use syntax::codemap::{Span, Spanned};
use syntax::parse::token;
use rustc_front::hir::*;
use rustc_front::fold::Folder;
-use rustc_front::visit::{self, Visitor};
-use rustc_front::util;
+use rustc_front::visit;
use rustc_front::print::pprust;
use arena::TypedArena;
use std::cell::RefCell;
use std::fmt;
use std::io;
-use std::iter::{self, repeat};
+use std::iter;
use std::mem;
use std::slice;
pub mod blocks;
+mod collector;
+pub mod definitions;
#[derive(Clone, Copy, PartialEq, Debug)]
pub enum PathElem {
NodeVariant(&'ast Variant),
NodeExpr(&'ast Expr),
NodeStmt(&'ast Stmt),
- NodeArg(&'ast Pat),
NodeLocal(&'ast Pat),
NodePat(&'ast Pat),
NodeBlock(&'ast Block),
/// NodeStructCtor represents a tuple struct.
- NodeStructCtor(&'ast StructDef),
+ NodeStructCtor(&'ast VariantData),
NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam)
/// Represents an entry and its parent NodeID.
/// The odd layout is to bring down the total size.
#[derive(Copy, Debug)]
-enum MapEntry<'ast> {
+pub enum MapEntry<'ast> {
/// Placeholder for holes in the map.
NotPresent,
EntryVariant(NodeId, &'ast Variant),
EntryExpr(NodeId, &'ast Expr),
EntryStmt(NodeId, &'ast Stmt),
- EntryArg(NodeId, &'ast Pat),
EntryLocal(NodeId, &'ast Pat),
EntryPat(NodeId, &'ast Pat),
EntryBlock(NodeId, &'ast Block),
- EntryStructCtor(NodeId, &'ast StructDef),
+ EntryStructCtor(NodeId, &'ast VariantData),
EntryLifetime(NodeId, &'ast Lifetime),
EntryTyParam(NodeId, &'ast TyParam),
NodeVariant(n) => EntryVariant(p, n),
NodeExpr(n) => EntryExpr(p, n),
NodeStmt(n) => EntryStmt(p, n),
- NodeArg(n) => EntryArg(p, n),
NodeLocal(n) => EntryLocal(p, n),
NodePat(n) => EntryPat(p, n),
NodeBlock(n) => EntryBlock(p, n),
EntryVariant(id, _) => id,
EntryExpr(id, _) => id,
EntryStmt(id, _) => id,
- EntryArg(id, _) => id,
EntryLocal(id, _) => id,
EntryPat(id, _) => id,
EntryBlock(id, _) => id,
EntryVariant(_, n) => NodeVariant(n),
EntryExpr(_, n) => NodeExpr(n),
EntryStmt(_, n) => NodeStmt(n),
- EntryArg(_, n) => NodeArg(n),
EntryLocal(_, n) => NodeLocal(n),
EntryPat(_, n) => NodePat(n),
EntryBlock(_, n) => NodeBlock(n),
///
/// Also, indexing is pretty quick when you've got a vector and
/// plain old integers.
- map: RefCell<Vec<MapEntry<'ast>>>
+ map: RefCell<Vec<MapEntry<'ast>>>,
+
+ definitions: RefCell<Definitions>,
}
impl<'ast> Map<'ast> {
+ pub fn num_local_def_ids(&self) -> usize {
+ self.definitions.borrow().len()
+ }
+
+ pub fn def_key(&self, def_id: DefId) -> DefKey {
+ assert!(def_id.is_local());
+ self.definitions.borrow().def_key(def_id.index)
+ }
+
+ pub fn def_path_from_id(&self, id: NodeId) -> DefPath {
+ self.def_path(self.local_def_id(id))
+ }
+
+ pub fn def_path(&self, def_id: DefId) -> DefPath {
+ assert!(def_id.is_local());
+ self.definitions.borrow().def_path(def_id.index)
+ }
+
+ pub fn local_def_id(&self, node: NodeId) -> DefId {
+ self.opt_local_def_id(node).unwrap_or_else(|| {
+ panic!("local_def_id: no entry for `{}`, which has a map of `{:?}`",
+ node, self.find_entry(node))
+ })
+ }
+
+ pub fn opt_local_def_id(&self, node: NodeId) -> Option<DefId> {
+ self.definitions.borrow().opt_local_def_id(node)
+ }
+
+ pub fn as_local_node_id(&self, def_id: DefId) -> Option<NodeId> {
+ self.definitions.borrow().as_local_node_id(def_id)
+ }
+
fn entry_count(&self) -> usize {
self.map.borrow().len()
}
}
}
+ pub fn get_if_local(&self, id: DefId) -> Option<Node<'ast>> {
+ self.as_local_node_id(id).map(|id| self.get(id))
+ }
+
/// Retrieve the Node corresponding to `id`, returning None if
/// cannot be found.
pub fn find(&self, id: NodeId) -> Option<Node<'ast>> {
self.find_entry(id).and_then(|x| x.parent_node()).unwrap_or(id)
}
+ /// Check if the node is an argument. An argument is a local variable whose
+ /// immediate parent is an item or a closure.
+ pub fn is_argument(&self, id: NodeId) -> bool {
+ match self.find(id) {
+ Some(NodeLocal(_)) => (),
+ _ => return false,
+ }
+ match self.find(self.get_parent_node(id)) {
+ Some(NodeItem(_)) |
+ Some(NodeTraitItem(_)) |
+ Some(NodeImplItem(_)) => true,
+ Some(NodeExpr(e)) => {
+ match e.node {
+ ExprClosure(..) => true,
+ _ => false,
+ }
+ }
+ _ => false,
+ }
+ }
+
/// If there is some error when walking the parents (e.g., a node does not
/// have a parent in the map or a node can't be found), then we return the
/// last good node id we found. Note that reaching the crate root (id == 0),
match self.find_entry(parent) {
Some(RootInlinedParent(&InlinedParent {ii: II::TraitItem(did, _), ..})) => did,
Some(RootInlinedParent(&InlinedParent {ii: II::ImplItem(did, _), ..})) => did,
- _ => DefId::local(parent)
+ _ => self.local_def_id(parent)
}
}
}
}
- pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef {
+ pub fn expect_struct(&self, id: NodeId) -> &'ast VariantData {
match self.find(id) {
Some(NodeItem(i)) => {
match i.node {
- ItemStruct(ref struct_def, _) => &**struct_def,
+ ItemStruct(ref struct_def, _) => struct_def,
_ => panic!("struct ID bound to non-struct")
}
}
Some(NodeVariant(variant)) => {
- match variant.node.kind {
- StructVariantKind(ref struct_def) => &**struct_def,
- _ => panic!("struct ID bound to enum variant that isn't struct-like"),
+ if variant.node.data.is_struct() {
+ &variant.node.data
+ } else {
+ panic!("struct ID bound to enum variant that isn't struct-like")
}
}
_ => panic!(format!("expected struct, found {}", self.node_to_string(id))),
NodeItem(item) => {
match item.node {
ItemMod(_) | ItemForeignMod(_) => {
- PathMod(item.ident.name)
+ PathMod(item.name)
}
- _ => PathName(item.ident.name)
+ _ => PathName(item.name)
}
}
- NodeForeignItem(i) => PathName(i.ident.name),
- NodeImplItem(ii) => PathName(ii.ident.name),
- NodeTraitItem(ti) => PathName(ti.ident.name),
- NodeVariant(v) => PathName(v.node.name.name),
+ NodeForeignItem(i) => PathName(i.name),
+ NodeImplItem(ii) => PathName(ii.name),
+ NodeTraitItem(ti) => PathName(ti.name),
+ NodeVariant(v) => PathName(v.node.name),
NodeLifetime(lt) => PathName(lt.name),
+ NodeTyParam(tp) => PathName(tp.name),
+ NodeLocal(&Pat { node: PatIdent(_,l,_), .. }) => {
+ PathName(l.node.name)
+ },
_ => panic!("no path elem for {:?}", node)
}
}
self.with_path(id, |path| path_to_string(path))
}
- fn path_to_str_with_ident(&self, id: NodeId, i: Ident) -> String {
+ fn path_to_str_with_name(&self, id: NodeId, name: Name) -> String {
self.with_path(id, |path| {
- path_to_string(path.chain(Some(PathName(i.name))))
+ path_to_string(path.chain(Some(PathName(name))))
})
}
}
}
- /// Given a node ID, get a list of of attributes associated with the AST
+ /// Given a node ID, get a list of attributes associated with the AST
/// corresponding to the Node ID
- pub fn attrs(&self, id: NodeId) -> &'ast [Attribute] {
+ pub fn attrs(&self, id: NodeId) -> &'ast [ast::Attribute] {
let attrs = match self.find(id) {
Some(NodeItem(i)) => Some(&i.attrs[..]),
Some(NodeForeignItem(fi)) => Some(&fi.attrs[..]),
Some(NodeVariant(variant)) => variant.span,
Some(NodeExpr(expr)) => expr.span,
Some(NodeStmt(stmt)) => stmt.span,
- Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span,
+ Some(NodeLocal(pat)) => pat.span,
Some(NodePat(pat)) => pat.span,
Some(NodeBlock(block)) => block.span,
Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span,
.unwrap_or_else(|| panic!("AstMap.span: could not find span for id {:?}", id))
}
+ pub fn span_if_local(&self, id: DefId) -> Option<Span> {
+ self.as_local_node_id(id).map(|id| self.span(id))
+ }
+
pub fn def_id_span(&self, def_id: DefId, fallback: Span) -> Span {
- if def_id.is_local() {
- self.opt_span(def_id.node).unwrap_or(fallback)
+ if let Some(node_id) = self.as_local_node_id(def_id) {
+ self.opt_span(node_id).unwrap_or(fallback)
} else {
fallback
}
match map.find(id) {
None => return None,
Some(NodeItem(item)) if item_is_mod(&*item) =>
- return Some((id, item.ident.name)),
+ return Some((id, item.name)),
_ => {}
}
let parent = map.get_parent(id);
impl<T:Named> Named for Spanned<T> { fn name(&self) -> Name { self.node.name() } }
-impl Named for Item { fn name(&self) -> Name { self.ident.name } }
-impl Named for ForeignItem { fn name(&self) -> Name { self.ident.name } }
-impl Named for Variant_ { fn name(&self) -> Name { self.name.name } }
-impl Named for TraitItem { fn name(&self) -> Name { self.ident.name } }
-impl Named for ImplItem { fn name(&self) -> Name { self.ident.name } }
+impl Named for Item { fn name(&self) -> Name { self.name } }
+impl Named for ForeignItem { fn name(&self) -> Name { self.name } }
+impl Named for Variant_ { fn name(&self) -> Name { self.name } }
+impl Named for TraitItem { fn name(&self) -> Name { self.name } }
+impl Named for ImplItem { fn name(&self) -> Name { self.name } }
pub trait FoldOps {
fn new_id(&self, id: NodeId) -> NodeId {
}
}
-/// A Visitor that walks over an AST and collects Node's into an AST Map.
-struct NodeCollector<'ast> {
- map: Vec<MapEntry<'ast>>,
- parent_node: NodeId,
-}
-
-impl<'ast> NodeCollector<'ast> {
- fn insert_entry(&mut self, id: NodeId, entry: MapEntry<'ast>) {
- debug!("ast_map: {:?} => {:?}", id, entry);
- let len = self.map.len();
- if id as usize >= len {
- self.map.extend(repeat(NotPresent).take(id as usize - len + 1));
- }
- self.map[id as usize] = entry;
- }
-
- fn insert(&mut self, id: NodeId, node: Node<'ast>) {
- let entry = MapEntry::from_node(self.parent_node, node);
- self.insert_entry(id, entry);
- }
-
- fn visit_fn_decl(&mut self, decl: &'ast FnDecl) {
- for a in &decl.inputs {
- self.insert(a.id, NodeArg(&*a.pat));
- }
- }
-}
-
-impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
- fn visit_item(&mut self, i: &'ast Item) {
- self.insert(i.id, NodeItem(i));
-
- let parent_node = self.parent_node;
- self.parent_node = i.id;
-
- match i.node {
- ItemImpl(_, _, _, _, _, ref impl_items) => {
- for ii in impl_items {
- self.insert(ii.id, NodeImplItem(ii));
- }
- }
- ItemEnum(ref enum_definition, _) => {
- for v in &enum_definition.variants {
- self.insert(v.node.id, NodeVariant(&**v));
- }
- }
- ItemForeignMod(ref nm) => {
- for nitem in &nm.items {
- self.insert(nitem.id, NodeForeignItem(&**nitem));
- }
- }
- ItemStruct(ref struct_def, _) => {
- // If this is a tuple-like struct, register the constructor.
- match struct_def.ctor_id {
- Some(ctor_id) => {
- self.insert(ctor_id, NodeStructCtor(&**struct_def));
- }
- None => {}
- }
- }
- ItemTrait(_, _, ref bounds, ref trait_items) => {
- for b in bounds.iter() {
- if let TraitTyParamBound(ref t, TraitBoundModifier::None) = *b {
- self.insert(t.trait_ref.ref_id, NodeItem(i));
- }
- }
-
- for ti in trait_items {
- self.insert(ti.id, NodeTraitItem(ti));
- }
- }
- ItemUse(ref view_path) => {
- match view_path.node {
- ViewPathList(_, ref paths) => {
- for path in paths {
- self.insert(path.node.id(), NodeItem(i));
- }
- }
- _ => ()
- }
- }
- _ => {}
- }
- visit::walk_item(self, i);
- self.parent_node = parent_node;
- }
-
- fn visit_generics(&mut self, generics: &'ast Generics) {
- for ty_param in generics.ty_params.iter() {
- self.insert(ty_param.id, NodeTyParam(ty_param));
- }
-
- visit::walk_generics(self, generics);
- }
-
- fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
- let parent_node = self.parent_node;
- self.parent_node = ti.id;
- visit::walk_trait_item(self, ti);
- self.parent_node = parent_node;
- }
-
- fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
- let parent_node = self.parent_node;
- self.parent_node = ii.id;
-
- visit::walk_impl_item(self, ii);
-
- self.parent_node = parent_node;
- }
-
- fn visit_pat(&mut self, pat: &'ast Pat) {
- self.insert(pat.id, match pat.node {
- // Note: this is at least *potentially* a pattern...
- PatIdent(..) => NodeLocal(pat),
- _ => NodePat(pat)
- });
-
- let parent_node = self.parent_node;
- self.parent_node = pat.id;
- visit::walk_pat(self, pat);
- self.parent_node = parent_node;
- }
-
- fn visit_expr(&mut self, expr: &'ast Expr) {
- self.insert(expr.id, NodeExpr(expr));
- let parent_node = self.parent_node;
- self.parent_node = expr.id;
- visit::walk_expr(self, expr);
- self.parent_node = parent_node;
- }
-
- fn visit_stmt(&mut self, stmt: &'ast Stmt) {
- let id = util::stmt_id(stmt);
- self.insert(id, NodeStmt(stmt));
- let parent_node = self.parent_node;
- self.parent_node = id;
- visit::walk_stmt(self, stmt);
- self.parent_node = parent_node;
- }
-
- fn visit_fn(&mut self, fk: visit::FnKind<'ast>, fd: &'ast FnDecl,
- b: &'ast Block, s: Span, id: NodeId) {
- let parent_node = self.parent_node;
- self.parent_node = id;
- self.visit_fn_decl(fd);
- visit::walk_fn(self, fk, fd, b, s);
- self.parent_node = parent_node;
- }
-
- fn visit_ty(&mut self, ty: &'ast Ty) {
- let parent_node = self.parent_node;
- self.parent_node = ty.id;
- match ty.node {
- TyBareFn(ref fd) => {
- self.visit_fn_decl(&*fd.decl);
- }
- _ => {}
- }
- visit::walk_ty(self, ty);
- self.parent_node = parent_node;
- }
-
- fn visit_block(&mut self, block: &'ast Block) {
- self.insert(block.id, NodeBlock(block));
- let parent_node = self.parent_node;
- self.parent_node = block.id;
- visit::walk_block(self, block);
- self.parent_node = parent_node;
- }
-
- fn visit_lifetime_ref(&mut self, lifetime: &'ast Lifetime) {
- self.insert(lifetime.id, NodeLifetime(lifetime));
- }
-
- fn visit_lifetime_def(&mut self, def: &'ast LifetimeDef) {
- self.visit_lifetime_ref(&def.lifetime);
- }
-}
-
pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
- let mut collector = NodeCollector {
- map: vec![],
- parent_node: CRATE_NODE_ID,
- };
- collector.insert_entry(CRATE_NODE_ID, RootCrate);
+ let mut collector = NodeCollector::root();
visit::walk_crate(&mut collector, &forest.krate);
- let map = collector.map;
+ let NodeCollector { map, definitions, .. } = collector;
if log_enabled!(::log::DEBUG) {
// This only makes sense for ordered stores; note the
Map {
forest: forest,
- map: RefCell::new(map)
+ map: RefCell::new(map),
+ definitions: RefCell::new(definitions),
}
}
/// the item itself.
pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
path: Vec<PathElem>,
+ def_path: DefPath,
ii: InlinedItem,
fold_ops: F)
-> &'ast InlinedItem {
});
let ii_parent_id = fld.new_id(DUMMY_NODE_ID);
- let mut collector = NodeCollector {
- map: mem::replace(&mut *map.map.borrow_mut(), vec![]),
- parent_node: ii_parent_id,
- };
- collector.insert_entry(ii_parent_id, RootInlinedParent(ii_parent));
+ let mut collector =
+ NodeCollector::extend(
+ ii_parent,
+ ii_parent_id,
+ def_path,
+ mem::replace(&mut *map.map.borrow_mut(), vec![]),
+ mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()));
ii_parent.ii.visit(&mut collector);
- // Methods get added to the AST map when their impl is visited. Since we
- // don't decode and instantiate the impl, but just the method, we have to
- // add it to the table now. Likewise with foreign items.
- match ii_parent.ii {
- II::Item(_) => {}
- II::TraitItem(_, ref ti) => {
- collector.insert(ti.id, NodeTraitItem(ti));
- }
- II::ImplItem(_, ref ii) => {
- collector.insert(ii.id, NodeImplItem(ii));
- }
- II::Foreign(ref i) => {
- collector.insert(i.id, NodeForeignItem(i));
- }
- }
*map.map.borrow_mut() = collector.map;
+ *map.definitions.borrow_mut() = collector.definitions;
+
&ii_parent.ii
}
// ast_map to reconstruct their full structure for pretty
// printing.
NodeLocal(_) => panic!("cannot print isolated Local"),
- NodeArg(_) => panic!("cannot print isolated Arg"),
NodeStructCtor(_) => panic!("cannot print isolated StructCtor"),
}
}
match map.find(id) {
Some(NodeItem(item)) => {
- let path_str = map.path_to_str_with_ident(id, item.ident);
+ let path_str = map.path_to_str_with_name(id, item.name);
let item_str = match item.node {
ItemExternCrate(..) => "extern crate",
ItemUse(..) => "use",
format!("{} {}{}", item_str, path_str, id_str)
}
Some(NodeForeignItem(item)) => {
- let path_str = map.path_to_str_with_ident(id, item.ident);
+ let path_str = map.path_to_str_with_name(id, item.name);
format!("foreign item {}{}", path_str, id_str)
}
Some(NodeImplItem(ii)) => {
match ii.node {
ConstImplItem(..) => {
format!("assoc const {} in {}{}",
- ii.ident,
+ ii.name,
map.path_to_string(id),
id_str)
}
MethodImplItem(..) => {
format!("method {} in {}{}",
- ii.ident,
+ ii.name,
map.path_to_string(id), id_str)
}
TypeImplItem(_) => {
format!("assoc type {} in {}{}",
- ii.ident,
+ ii.name,
map.path_to_string(id),
id_str)
}
format!("{} {} in {}{}",
kind,
- ti.ident,
+ ti.name,
map.path_to_string(id),
id_str)
}
Some(NodeStmt(ref stmt)) => {
format!("stmt {}{}", pprust::stmt_to_string(&**stmt), id_str)
}
- Some(NodeArg(ref pat)) => {
- format!("arg {}{}", pprust::pat_to_string(&**pat), id_str)
- }
Some(NodeLocal(ref pat)) => {
format!("local {}{}", pprust::pat_to_string(&**pat), id_str)
}
#![feature(duration_span)]
#![feature(dynamic_lib)]
#![feature(enumset)]
-#![feature(fs_canonicalize)]
#![feature(hashmap_hasher)]
#![feature(into_cow)]
#![feature(iter_cmp)]
#![feature(libc)]
#![feature(nonzero)]
#![feature(num_bits_bytes)]
-#![feature(path_ext)]
#![feature(quote)]
-#![feature(range_inclusive)]
-#![feature(ref_slice)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(scoped_tls)]
-#![feature(slice_splits)]
#![feature(slice_patterns)]
#![feature(staged_api)]
#![feature(str_char)]
-#![feature(str_match_indices)]
#![feature(vec_push_all)]
#![feature(wrapping)]
#![feature(cell_extras)]
}
pub mod front {
+ pub mod check_attr;
pub mod map;
}
pub mod middle {
+ pub mod expr_use_visitor; // STAGE0: increase glitch immunity
pub mod astconv_util;
pub mod astencode;
pub mod cfg;
pub mod dependency_format;
pub mod effect;
pub mod entry;
- pub mod expr_use_visitor;
pub mod free_region;
pub mod intrinsicck;
pub mod infer;
//! compiler code, rather than using their own custom pass. Those
//! lints are all available in `rustc_lint::builtin`.
-use lint::{LintPass, LintArray};
+use lint::{LintPass, LateLintPass, LintArray};
+
+declare_lint! {
+ pub CONST_ERR,
+ Warn,
+ "constant evaluation detected erroneous expression"
+}
declare_lint! {
pub UNUSED_IMPORTS,
VARIANT_SIZE_DIFFERENCES,
FAT_PTR_TRANSMUTES,
TRIVIAL_CASTS,
- TRIVIAL_NUMERIC_CASTS
+ TRIVIAL_NUMERIC_CASTS,
+ CONST_ERR
)
}
}
+
+impl LateLintPass for HardwiredLints {}
use middle::privacy::ExportedItems;
use middle::ty::{self, Ty};
use session::{early_error, Session};
-use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass, LintPassObject};
+use lint::{Level, LevelSource, Lint, LintId, LintArray, LintPass};
+use lint::{EarlyLintPass, EarlyLintPassObject, LateLintPass, LateLintPassObject};
use lint::{Default, CommandLine, Node, Allow, Warn, Deny, Forbid};
use lint::builtin;
use util::nodemap::FnvHashMap;
use std::cell::RefCell;
use std::cmp;
use std::mem;
-use syntax::ast_util::IdVisitingOperation;
-use rustc_front::attr::{self, AttrMetaMethods};
-use rustc_front::util;
+use syntax::ast_util::{self, IdVisitingOperation};
+use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use syntax::ast;
use rustc_front::hir;
-use rustc_front::visit::{self, Visitor, FnKind};
-use syntax::visit::Visitor as SyntaxVisitor;
+use rustc_front::util;
+use rustc_front::visit as hir_visit;
+use syntax::visit as ast_visit;
use syntax::diagnostic;
/// Information about the registered lints.
/// Trait objects for each lint pass.
/// This is only `None` while iterating over the objects. See the definition
/// of run_lints.
- passes: Option<Vec<LintPassObject>>,
+ early_passes: Option<Vec<EarlyLintPassObject>>,
+ late_passes: Option<Vec<LateLintPassObject>>,
/// Lints indexed by name.
by_name: FnvHashMap<String, TargetLint>,
pub fn new() -> LintStore {
LintStore {
lints: vec!(),
- passes: Some(vec!()),
+ early_passes: Some(vec!()),
+ late_passes: Some(vec!()),
by_name: FnvHashMap(),
levels: FnvHashMap(),
lint_groups: FnvHashMap(),
v.1)).collect()
}
- pub fn register_pass(&mut self, sess: Option<&Session>,
- from_plugin: bool, pass: LintPassObject) {
+ pub fn register_early_pass(&mut self,
+ sess: Option<&Session>,
+ from_plugin: bool,
+ pass: EarlyLintPassObject) {
+ self.push_pass(sess, from_plugin, &pass);
+ self.early_passes.as_mut().unwrap().push(pass);
+ }
+
+ pub fn register_late_pass(&mut self,
+ sess: Option<&Session>,
+ from_plugin: bool,
+ pass: LateLintPassObject) {
+ self.push_pass(sess, from_plugin, &pass);
+ self.late_passes.as_mut().unwrap().push(pass);
+ }
+
+ // Helper method for register_early/late_pass
+ fn push_pass<P: LintPass + ?Sized + 'static>(&mut self,
+ sess: Option<&Session>,
+ from_plugin: bool,
+ pass: &Box<P>) {
for &lint in pass.get_lints() {
self.lints.push((*lint, from_plugin));
self.levels.insert(id, (lint.default_level, Default));
}
}
- self.passes.as_mut().unwrap().push(pass);
}
pub fn register_group(&mut self, sess: Option<&Session>,
}
}
-/// Context for lint checking.
-pub struct Context<'a, 'tcx: 'a> {
+/// Context for lint checking after type checking.
+pub struct LateContext<'a, 'tcx: 'a> {
/// Type context we're checking in.
pub tcx: &'a ty::ctxt<'tcx>,
node_levels: RefCell<FnvHashMap<(ast::NodeId, LintId), LevelSource>>,
}
+/// Context for lint checking of the AST, after expansion, before lowering to
+/// HIR.
+pub struct EarlyContext<'a> {
+ /// Type context we're checking in.
+ pub sess: &'a Session,
+
+ /// The crate being checked.
+ pub krate: &'a ast::Crate,
+
+ /// The store of registered lints.
+ lints: LintStore,
+
+ /// When recursing into an attributed node of the ast which modifies lint
+ /// levels, this stack keeps track of the previous lint levels of whatever
+ /// was modified.
+ level_stack: Vec<(LintId, LevelSource)>,
+}
+
/// Convenience macro for calling a `LintPass` method on every pass in the context.
-macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({
+macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({
// Move the vector of passes out of `$cx` so that we can
// iterate over it mutably while passing `$cx` to the methods.
- let mut passes = $cx.lints.passes.take().unwrap();
+ let mut passes = $cx.mut_lints().$ps.take().unwrap();
for obj in &mut passes {
obj.$f($cx, $($args),*);
}
- $cx.lints.passes = Some(passes);
+ $cx.mut_lints().$ps = Some(passes);
}) }
/// Parse the lint attributes into a vector, with `Err`s for malformed lint
/// attributes. Writing this as an iterator is an enormous mess.
// See also the hir version just below.
-pub fn gather_attrs(attrs: &[hir::Attribute])
+pub fn gather_attrs(attrs: &[ast::Attribute])
-> Vec<Result<(InternedString, Level, Span), Span>> {
let mut out = vec!();
for attr in attrs {
let meta = &attr.node.value;
let metas = match meta.node {
- hir::MetaList(_, ref metas) => metas,
+ ast::MetaList(_, ref metas) => metas,
_ => {
out.push(Err(meta.span));
continue;
for meta in metas {
out.push(match meta.node {
- hir::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
- _ => Err(meta.span),
- });
- }
- }
- out
-}
-// Copy-pasted from the above function :-(
-pub fn gather_attrs_from_hir(attrs: &[::rustc_front::hir::Attribute])
- -> Vec<Result<(InternedString, Level, Span), Span>> {
- use ::rustc_front::attr::AttrMetaMethods;
-
- let mut out = vec!();
- for attr in attrs {
- let level = match Level::from_str(&attr.name()) {
- None => continue,
- Some(lvl) => lvl,
- };
-
- ::rustc_front::attr::mark_used(attr);
-
- let meta = &attr.node.value;
- let metas = match meta.node {
- ::rustc_front::hir::MetaList(_, ref metas) => metas,
- _ => {
- out.push(Err(meta.span));
- continue;
- }
- };
-
- for meta in metas {
- out.push(match meta.node {
- ::rustc_front::hir::MetaWord(ref lint_name) => {
- Ok((lint_name.clone(), level, meta.span))
- }
+ ast::MetaWord(ref lint_name) => Ok((lint_name.clone(), level, meta.span)),
_ => Err(meta.span),
});
}
}
}
-impl<'a, 'tcx> Context<'a, 'tcx> {
- fn new(tcx: &'a ty::ctxt<'tcx>,
- krate: &'a hir::Crate,
- exported_items: &'a ExportedItems) -> Context<'a, 'tcx> {
- // We want to own the lint store, so move it out of the session.
- let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
- LintStore::new());
-
- Context {
- tcx: tcx,
- krate: krate,
- exported_items: exported_items,
- lints: lint_store,
- level_stack: vec![],
- node_levels: RefCell::new(FnvHashMap()),
- }
- }
-
- /// Get the overall compiler `Session` object.
- pub fn sess(&'a self) -> &'a Session {
- &self.tcx.sess
- }
+pub trait LintContext: Sized {
+ fn sess(&self) -> &Session;
+ fn lints(&self) -> &LintStore;
+ fn mut_lints(&mut self) -> &mut LintStore;
+ fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)>;
+ fn enter_attrs(&mut self, attrs: &[ast::Attribute]);
+ fn exit_attrs(&mut self, attrs: &[ast::Attribute]);
/// Get the level of `lint` at the current position of the lint
/// traversal.
- pub fn current_level(&self, lint: &'static Lint) -> Level {
- self.lints.levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
+ fn current_level(&self, lint: &'static Lint) -> Level {
+ self.lints().levels.get(&LintId::of(lint)).map_or(Allow, |&(lvl, _)| lvl)
}
fn lookup_and_emit(&self, lint: &'static Lint, span: Option<Span>, msg: &str) {
- let (level, src) = match self.lints.levels.get(&LintId::of(lint)) {
+ let (level, src) = match self.lints().levels.get(&LintId::of(lint)) {
None => return,
Some(&(Warn, src)) => {
let lint_id = LintId::of(builtin::WARNINGS);
- (self.lints.get_level_source(lint_id).0, src)
+ (self.lints().get_level_source(lint_id).0, src)
}
Some(&pair) => pair,
};
- raw_emit_lint(&self.tcx.sess, lint, (level, src), span, msg);
- }
-
- /// Emit a lint at the appropriate level, with no associated span.
- pub fn lint(&self, lint: &'static Lint, msg: &str) {
- self.lookup_and_emit(lint, None, msg);
+ raw_emit_lint(&self.sess(), lint, (level, src), span, msg);
}
/// Emit a lint at the appropriate level, for a particular span.
- pub fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
+ fn span_lint(&self, lint: &'static Lint, span: Span, msg: &str) {
self.lookup_and_emit(lint, Some(span), msg);
}
+ /// Emit a lint and note at the appropriate level, for a particular span.
+ fn span_lint_note(&self, lint: &'static Lint, span: Span, msg: &str,
+ note_span: Span, note: &str) {
+ self.span_lint(lint, span, msg);
+ if self.current_level(lint) != Level::Allow {
+ if note_span == span {
+ self.sess().fileline_note(note_span, note)
+ } else {
+ self.sess().span_note(note_span, note)
+ }
+ }
+ }
+
+ /// Emit a lint and help at the appropriate level, for a particular span.
+ fn span_lint_help(&self, lint: &'static Lint, span: Span,
+ msg: &str, help: &str) {
+ self.span_lint(lint, span, msg);
+ if self.current_level(lint) != Level::Allow {
+ self.sess().span_help(span, help)
+ }
+ }
+
+ /// Emit a lint at the appropriate level, with no associated span.
+ fn lint(&self, lint: &'static Lint, msg: &str) {
+ self.lookup_and_emit(lint, None, msg);
+ }
+
/// Merge the lints specified by any lint attributes into the
/// current lint context, call the provided function, then reset the
/// lints in effect to their previous state.
fn with_lint_attrs<F>(&mut self,
- attrs: &[hir::Attribute],
- f: F) where
- F: FnOnce(&mut Context),
+ attrs: &[ast::Attribute],
+ f: F)
+ where F: FnOnce(&mut Self),
{
// Parse all of the lint attributes, and then add them all to the
// current dictionary of lint information. Along the way, keep a history
for result in gather_attrs(attrs) {
let v = match result {
Err(span) => {
- self.tcx.sess.span_err(span, "malformed lint attribute");
+ span_err!(self.sess(), span, E0452,
+ "malformed lint attribute");
continue;
}
Ok((lint_name, level, span)) => {
- match self.lints.find_lint(&lint_name, &self.tcx.sess, Some(span)) {
+ match self.lints().find_lint(&lint_name, &self.sess(), Some(span)) {
Ok(lint_id) => vec![(lint_id, level, span)],
Err(FindLintError::NotFound) => {
- match self.lints.lint_groups.get(&lint_name[..]) {
+ match self.lints().lint_groups.get(&lint_name[..]) {
Some(&(ref v, _)) => v.iter()
.map(|lint_id: &LintId|
(*lint_id, level, span))
};
for (lint_id, level, span) in v {
- let now = self.lints.get_level_source(lint_id).0;
+ let now = self.lints().get_level_source(lint_id).0;
if now == Forbid && level != Forbid {
let lint_name = lint_id.as_str();
- self.tcx.sess.span_err(span,
- &format!("{}({}) overruled by outer forbid({})",
- level.as_str(), lint_name,
- lint_name));
+ span_err!(self.sess(), span, E0453,
+ "{}({}) overruled by outer forbid({})",
+ level.as_str(), lint_name,
+ lint_name);
} else if now != level {
- let src = self.lints.get_level_source(lint_id).1;
- self.level_stack.push((lint_id, (now, src)));
+ let src = self.lints().get_level_source(lint_id).1;
+ self.level_stack().push((lint_id, (now, src)));
pushed += 1;
- self.lints.set_level(lint_id, (level, Node(span)));
+ self.mut_lints().set_level(lint_id, (level, Node(span)));
}
}
}
- run_lints!(self, enter_lint_attrs, attrs);
+ self.enter_attrs(attrs);
f(self);
- run_lints!(self, exit_lint_attrs, attrs);
+ self.exit_attrs(attrs);
// rollback
for _ in 0..pushed {
- let (lint, lvlsrc) = self.level_stack.pop().unwrap();
- self.lints.set_level(lint, lvlsrc);
+ let (lint, lvlsrc) = self.level_stack().pop().unwrap();
+ self.mut_lints().set_level(lint, lvlsrc);
+ }
+ }
+}
+
+
+impl<'a> EarlyContext<'a> {
+ fn new(sess: &'a Session,
+ krate: &'a ast::Crate) -> EarlyContext<'a> {
+ // We want to own the lint store, so move it out of the session. Remember
+ // to put it back later...
+ let lint_store = mem::replace(&mut *sess.lint_store.borrow_mut(),
+ LintStore::new());
+ EarlyContext {
+ sess: sess,
+ krate: krate,
+ lints: lint_store,
+ level_stack: vec![],
+ }
+ }
+
+ fn visit_ids<F>(&mut self, f: F)
+ where F: FnOnce(&mut ast_util::IdVisitor<EarlyContext>)
+ {
+ let mut v = ast_util::IdVisitor {
+ operation: self,
+ pass_through_items: false,
+ visited_outermost: false,
+ };
+ f(&mut v);
+ }
+}
+
+impl<'a, 'tcx> LateContext<'a, 'tcx> {
+ fn new(tcx: &'a ty::ctxt<'tcx>,
+ krate: &'a hir::Crate,
+ exported_items: &'a ExportedItems) -> LateContext<'a, 'tcx> {
+ // We want to own the lint store, so move it out of the session.
+ let lint_store = mem::replace(&mut *tcx.sess.lint_store.borrow_mut(),
+ LintStore::new());
+
+ LateContext {
+ tcx: tcx,
+ krate: krate,
+ exported_items: exported_items,
+ lints: lint_store,
+ level_stack: vec![],
+ node_levels: RefCell::new(FnvHashMap()),
}
}
- fn visit_ids<F>(&mut self, f: F) where
- F: FnOnce(&mut util::IdVisitor<Context>)
+ fn visit_ids<F>(&mut self, f: F)
+ where F: FnOnce(&mut util::IdVisitor<LateContext>)
{
let mut v = util::IdVisitor {
operation: self,
}
}
-impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
+impl<'a, 'tcx> LintContext for LateContext<'a, 'tcx> {
+ /// Get the overall compiler `Session` object.
+ fn sess(&self) -> &Session {
+ &self.tcx.sess
+ }
+
+ fn lints(&self) -> &LintStore {
+ &self.lints
+ }
+
+ fn mut_lints(&mut self) -> &mut LintStore {
+ &mut self.lints
+ }
+
+ fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
+ &mut self.level_stack
+ }
+
+ fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
+ run_lints!(self, enter_lint_attrs, late_passes, attrs);
+ }
+
+ fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
+ run_lints!(self, exit_lint_attrs, late_passes, attrs);
+ }
+}
+
+impl<'a> LintContext for EarlyContext<'a> {
+ /// Get the overall compiler `Session` object.
+ fn sess(&self) -> &Session {
+ &self.sess
+ }
+
+ fn lints(&self) -> &LintStore {
+ &self.lints
+ }
+
+ fn mut_lints(&mut self) -> &mut LintStore {
+ &mut self.lints
+ }
+
+ fn level_stack(&mut self) -> &mut Vec<(LintId, LevelSource)> {
+ &mut self.level_stack
+ }
+
+ fn enter_attrs(&mut self, attrs: &[ast::Attribute]) {
+ run_lints!(self, enter_lint_attrs, early_passes, attrs);
+ }
+
+ fn exit_attrs(&mut self, attrs: &[ast::Attribute]) {
+ run_lints!(self, exit_lint_attrs, early_passes, attrs);
+ }
+}
+
+impl<'a, 'tcx, 'v> hir_visit::Visitor<'v> for LateContext<'a, 'tcx> {
fn visit_item(&mut self, it: &hir::Item) {
self.with_lint_attrs(&it.attrs, |cx| {
- run_lints!(cx, check_item, it);
+ run_lints!(cx, check_item, late_passes, it);
cx.visit_ids(|v| v.visit_item(it));
- visit::walk_item(cx, it);
+ hir_visit::walk_item(cx, it);
})
}
fn visit_foreign_item(&mut self, it: &hir::ForeignItem) {
self.with_lint_attrs(&it.attrs, |cx| {
- run_lints!(cx, check_foreign_item, it);
- visit::walk_foreign_item(cx, it);
+ run_lints!(cx, check_foreign_item, late_passes, it);
+ hir_visit::walk_foreign_item(cx, it);
})
}
fn visit_pat(&mut self, p: &hir::Pat) {
- run_lints!(self, check_pat, p);
- visit::walk_pat(self, p);
+ run_lints!(self, check_pat, late_passes, p);
+ hir_visit::walk_pat(self, p);
}
fn visit_expr(&mut self, e: &hir::Expr) {
- run_lints!(self, check_expr, e);
- visit::walk_expr(self, e);
+ run_lints!(self, check_expr, late_passes, e);
+ hir_visit::walk_expr(self, e);
}
fn visit_stmt(&mut self, s: &hir::Stmt) {
- run_lints!(self, check_stmt, s);
- visit::walk_stmt(self, s);
+ run_lints!(self, check_stmt, late_passes, s);
+ hir_visit::walk_stmt(self, s);
}
- fn visit_fn(&mut self, fk: FnKind<'v>, decl: &'v hir::FnDecl,
+ fn visit_fn(&mut self, fk: hir_visit::FnKind<'v>, decl: &'v hir::FnDecl,
body: &'v hir::Block, span: Span, id: ast::NodeId) {
- run_lints!(self, check_fn, fk, decl, body, span, id);
- visit::walk_fn(self, fk, decl, body, span);
+ run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
+ hir_visit::walk_fn(self, fk, decl, body, span);
}
- fn visit_struct_def(&mut self,
- s: &hir::StructDef,
- ident: ast::Ident,
+ fn visit_variant_data(&mut self,
+ s: &hir::VariantData,
+ name: ast::Name,
g: &hir::Generics,
- id: ast::NodeId) {
- run_lints!(self, check_struct_def, s, ident, g, id);
- visit::walk_struct_def(self, s);
- run_lints!(self, check_struct_def_post, s, ident, g, id);
+ item_id: ast::NodeId,
+ _: Span) {
+ run_lints!(self, check_struct_def, late_passes, s, name, g, item_id);
+ hir_visit::walk_struct_def(self, s);
+ run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id);
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
self.with_lint_attrs(&s.node.attrs, |cx| {
- run_lints!(cx, check_struct_field, s);
- visit::walk_struct_field(cx, s);
+ run_lints!(cx, check_struct_field, late_passes, s);
+ hir_visit::walk_struct_field(cx, s);
})
}
- fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) {
+ fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
self.with_lint_attrs(&v.node.attrs, |cx| {
- run_lints!(cx, check_variant, v, g);
- visit::walk_variant(cx, v, g);
- run_lints!(cx, check_variant_post, v, g);
+ run_lints!(cx, check_variant, late_passes, v, g);
+ hir_visit::walk_variant(cx, v, g, item_id);
+ run_lints!(cx, check_variant_post, late_passes, v, g);
})
}
fn visit_ty(&mut self, t: &hir::Ty) {
- run_lints!(self, check_ty, t);
- visit::walk_ty(self, t);
+ run_lints!(self, check_ty, late_passes, t);
+ hir_visit::walk_ty(self, t);
}
- fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
- run_lints!(self, check_ident, sp, id);
+ fn visit_name(&mut self, sp: Span, name: ast::Name) {
+ run_lints!(self, check_name, late_passes, sp, name);
}
fn visit_mod(&mut self, m: &hir::Mod, s: Span, n: ast::NodeId) {
- run_lints!(self, check_mod, m, s, n);
- visit::walk_mod(self, m);
+ run_lints!(self, check_mod, late_passes, m, s, n);
+ hir_visit::walk_mod(self, m);
}
fn visit_local(&mut self, l: &hir::Local) {
- run_lints!(self, check_local, l);
- visit::walk_local(self, l);
+ run_lints!(self, check_local, late_passes, l);
+ hir_visit::walk_local(self, l);
}
fn visit_block(&mut self, b: &hir::Block) {
- run_lints!(self, check_block, b);
- visit::walk_block(self, b);
+ run_lints!(self, check_block, late_passes, b);
+ hir_visit::walk_block(self, b);
}
fn visit_arm(&mut self, a: &hir::Arm) {
- run_lints!(self, check_arm, a);
- visit::walk_arm(self, a);
+ run_lints!(self, check_arm, late_passes, a);
+ hir_visit::walk_arm(self, a);
}
fn visit_decl(&mut self, d: &hir::Decl) {
- run_lints!(self, check_decl, d);
- visit::walk_decl(self, d);
+ run_lints!(self, check_decl, late_passes, d);
+ hir_visit::walk_decl(self, d);
}
fn visit_expr_post(&mut self, e: &hir::Expr) {
- run_lints!(self, check_expr_post, e);
+ run_lints!(self, check_expr_post, late_passes, e);
}
fn visit_generics(&mut self, g: &hir::Generics) {
- run_lints!(self, check_generics, g);
- visit::walk_generics(self, g);
+ run_lints!(self, check_generics, late_passes, g);
+ hir_visit::walk_generics(self, g);
}
fn visit_trait_item(&mut self, trait_item: &hir::TraitItem) {
self.with_lint_attrs(&trait_item.attrs, |cx| {
- run_lints!(cx, check_trait_item, trait_item);
+ run_lints!(cx, check_trait_item, late_passes, trait_item);
cx.visit_ids(|v| v.visit_trait_item(trait_item));
- visit::walk_trait_item(cx, trait_item);
+ hir_visit::walk_trait_item(cx, trait_item);
});
}
fn visit_impl_item(&mut self, impl_item: &hir::ImplItem) {
self.with_lint_attrs(&impl_item.attrs, |cx| {
- run_lints!(cx, check_impl_item, impl_item);
+ run_lints!(cx, check_impl_item, late_passes, impl_item);
cx.visit_ids(|v| v.visit_impl_item(impl_item));
- visit::walk_impl_item(cx, impl_item);
+ hir_visit::walk_impl_item(cx, impl_item);
});
}
- fn visit_opt_lifetime_ref(&mut self, sp: Span, lt: &Option<hir::Lifetime>) {
- run_lints!(self, check_opt_lifetime_ref, sp, lt);
- }
-
- fn visit_lifetime_ref(&mut self, lt: &hir::Lifetime) {
- run_lints!(self, check_lifetime_ref, lt);
+ fn visit_lifetime(&mut self, lt: &hir::Lifetime) {
+ run_lints!(self, check_lifetime, late_passes, lt);
}
fn visit_lifetime_def(&mut self, lt: &hir::LifetimeDef) {
- run_lints!(self, check_lifetime_def, lt);
+ run_lints!(self, check_lifetime_def, late_passes, lt);
}
fn visit_explicit_self(&mut self, es: &hir::ExplicitSelf) {
- run_lints!(self, check_explicit_self, es);
- visit::walk_explicit_self(self, es);
+ run_lints!(self, check_explicit_self, late_passes, es);
+ hir_visit::walk_explicit_self(self, es);
}
fn visit_path(&mut self, p: &hir::Path, id: ast::NodeId) {
- run_lints!(self, check_path, p, id);
- visit::walk_path(self, p);
+ run_lints!(self, check_path, late_passes, p, id);
+ hir_visit::walk_path(self, p);
+ }
+
+ fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
+ run_lints!(self, check_path_list_item, late_passes, item);
+ hir_visit::walk_path_list_item(self, prefix, item);
}
- fn visit_attribute(&mut self, attr: &hir::Attribute) {
- run_lints!(self, check_attribute, attr);
+ fn visit_attribute(&mut self, attr: &ast::Attribute) {
+ run_lints!(self, check_attribute, late_passes, attr);
+ }
+}
+
+impl<'a, 'v> ast_visit::Visitor<'v> for EarlyContext<'a> {
+ fn visit_item(&mut self, it: &ast::Item) {
+ self.with_lint_attrs(&it.attrs, |cx| {
+ run_lints!(cx, check_item, early_passes, it);
+ cx.visit_ids(|v| v.visit_item(it));
+ ast_visit::walk_item(cx, it);
+ })
+ }
+
+ fn visit_foreign_item(&mut self, it: &ast::ForeignItem) {
+ self.with_lint_attrs(&it.attrs, |cx| {
+ run_lints!(cx, check_foreign_item, early_passes, it);
+ ast_visit::walk_foreign_item(cx, it);
+ })
+ }
+
+ fn visit_pat(&mut self, p: &ast::Pat) {
+ run_lints!(self, check_pat, early_passes, p);
+ ast_visit::walk_pat(self, p);
+ }
+
+ fn visit_expr(&mut self, e: &ast::Expr) {
+ run_lints!(self, check_expr, early_passes, e);
+ ast_visit::walk_expr(self, e);
+ }
+
+ fn visit_stmt(&mut self, s: &ast::Stmt) {
+ run_lints!(self, check_stmt, early_passes, s);
+ ast_visit::walk_stmt(self, s);
+ }
+
+ fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, decl: &'v ast::FnDecl,
+ body: &'v ast::Block, span: Span, id: ast::NodeId) {
+ run_lints!(self, check_fn, early_passes, fk, decl, body, span, id);
+ ast_visit::walk_fn(self, fk, decl, body, span);
+ }
+
+ fn visit_variant_data(&mut self,
+ s: &ast::VariantData,
+ ident: ast::Ident,
+ g: &ast::Generics,
+ item_id: ast::NodeId,
+ _: Span) {
+ run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id);
+ ast_visit::walk_struct_def(self, s);
+ run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id);
+ }
+
+ fn visit_struct_field(&mut self, s: &ast::StructField) {
+ self.with_lint_attrs(&s.node.attrs, |cx| {
+ run_lints!(cx, check_struct_field, early_passes, s);
+ ast_visit::walk_struct_field(cx, s);
+ })
+ }
+
+ fn visit_variant(&mut self, v: &ast::Variant, g: &ast::Generics, item_id: ast::NodeId) {
+ self.with_lint_attrs(&v.node.attrs, |cx| {
+ run_lints!(cx, check_variant, early_passes, v, g);
+ ast_visit::walk_variant(cx, v, g, item_id);
+ run_lints!(cx, check_variant_post, early_passes, v, g);
+ })
+ }
+
+ fn visit_ty(&mut self, t: &ast::Ty) {
+ run_lints!(self, check_ty, early_passes, t);
+ ast_visit::walk_ty(self, t);
+ }
+
+ fn visit_ident(&mut self, sp: Span, id: ast::Ident) {
+ run_lints!(self, check_ident, early_passes, sp, id);
+ }
+
+ fn visit_mod(&mut self, m: &ast::Mod, s: Span, n: ast::NodeId) {
+ run_lints!(self, check_mod, early_passes, m, s, n);
+ ast_visit::walk_mod(self, m);
+ }
+
+ fn visit_local(&mut self, l: &ast::Local) {
+ run_lints!(self, check_local, early_passes, l);
+ ast_visit::walk_local(self, l);
+ }
+
+ fn visit_block(&mut self, b: &ast::Block) {
+ run_lints!(self, check_block, early_passes, b);
+ ast_visit::walk_block(self, b);
+ }
+
+ fn visit_arm(&mut self, a: &ast::Arm) {
+ run_lints!(self, check_arm, early_passes, a);
+ ast_visit::walk_arm(self, a);
+ }
+
+ fn visit_decl(&mut self, d: &ast::Decl) {
+ run_lints!(self, check_decl, early_passes, d);
+ ast_visit::walk_decl(self, d);
+ }
+
+ fn visit_expr_post(&mut self, e: &ast::Expr) {
+ run_lints!(self, check_expr_post, early_passes, e);
+ }
+
+ fn visit_generics(&mut self, g: &ast::Generics) {
+ run_lints!(self, check_generics, early_passes, g);
+ ast_visit::walk_generics(self, g);
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
+ self.with_lint_attrs(&trait_item.attrs, |cx| {
+ run_lints!(cx, check_trait_item, early_passes, trait_item);
+ cx.visit_ids(|v| v.visit_trait_item(trait_item));
+ ast_visit::walk_trait_item(cx, trait_item);
+ });
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
+ self.with_lint_attrs(&impl_item.attrs, |cx| {
+ run_lints!(cx, check_impl_item, early_passes, impl_item);
+ cx.visit_ids(|v| v.visit_impl_item(impl_item));
+ ast_visit::walk_impl_item(cx, impl_item);
+ });
+ }
+
+ fn visit_lifetime(&mut self, lt: &ast::Lifetime) {
+ run_lints!(self, check_lifetime, early_passes, lt);
+ }
+
+ fn visit_lifetime_def(&mut self, lt: &ast::LifetimeDef) {
+ run_lints!(self, check_lifetime_def, early_passes, lt);
+ }
+
+ fn visit_explicit_self(&mut self, es: &ast::ExplicitSelf) {
+ run_lints!(self, check_explicit_self, early_passes, es);
+ ast_visit::walk_explicit_self(self, es);
+ }
+
+ fn visit_path(&mut self, p: &ast::Path, id: ast::NodeId) {
+ run_lints!(self, check_path, early_passes, p, id);
+ ast_visit::walk_path(self, p);
+ }
+
+ fn visit_path_list_item(&mut self, prefix: &ast::Path, item: &ast::PathListItem) {
+ run_lints!(self, check_path_list_item, early_passes, item);
+ ast_visit::walk_path_list_item(self, prefix, item);
+ }
+
+ fn visit_attribute(&mut self, attr: &ast::Attribute) {
+ run_lints!(self, check_attribute, early_passes, attr);
}
}
// Output any lints that were previously added to the session.
-impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> {
+impl<'a, 'tcx> IdVisitingOperation for LateContext<'a, 'tcx> {
+ fn visit_id(&mut self, id: ast::NodeId) {
+ match self.sess().lints.borrow_mut().remove(&id) {
+ None => {}
+ Some(lints) => {
+ for (lint_id, span, msg) in lints {
+ self.span_lint(lint_id.lint, span, &msg[..])
+ }
+ }
+ }
+ }
+}
+impl<'a> IdVisitingOperation for EarlyContext<'a> {
fn visit_id(&mut self, id: ast::NodeId) {
- match self.tcx.sess.lints.borrow_mut().remove(&id) {
+ match self.sess.lints.borrow_mut().remove(&id) {
None => {}
Some(lints) => {
for (lint_id, span, msg) in lints {
}
}
-// This lint pass is defined here because it touches parts of the `Context`
+// This lint pass is defined here because it touches parts of the `LateContext`
// that we don't want to expose. It records the lint level at certain AST
// nodes, so that the variant size difference check in trans can call
// `raw_emit_lint`.
fn get_lints(&self) -> LintArray {
lint_array!()
}
+}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
+impl LateLintPass for GatherNodeLevels {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemEnum(..) => {
let lint_id = LintId::of(builtin::VARIANT_SIZE_DIFFERENCES);
krate: &hir::Crate,
exported_items: &ExportedItems) {
- let mut cx = Context::new(tcx, krate, exported_items);
+ let mut cx = LateContext::new(tcx, krate, exported_items);
// Visit the whole crate.
cx.with_lint_attrs(&krate.attrs, |cx| {
cx.visit_id(ast::CRATE_NODE_ID);
cx.visit_ids(|v| {
v.visited_outermost = true;
- visit::walk_crate(v, krate);
+ hir_visit::walk_crate(v, krate);
});
// since the root module isn't visited as an item (because it isn't an
// item), warn for it here.
- run_lints!(cx, check_crate, krate);
+ run_lints!(cx, check_crate, late_passes, krate);
- visit::walk_crate(cx, krate);
+ hir_visit::walk_crate(cx, krate);
});
// If we missed any lints added to the session, then there's a bug somewhere
*tcx.node_lint_levels.borrow_mut() = cx.node_levels.into_inner();
}
+
+pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) {
+ let mut cx = EarlyContext::new(sess, krate);
+
+ // Visit the whole crate.
+ cx.with_lint_attrs(&krate.attrs, |cx| {
+ cx.visit_id(ast::CRATE_NODE_ID);
+ cx.visit_ids(|v| {
+ v.visited_outermost = true;
+ ast_visit::walk_crate(v, krate);
+ });
+
+ // since the root module isn't visited as an item (because it isn't an
+ // item), warn for it here.
+ run_lints!(cx, check_crate, early_passes, krate);
+
+ ast_visit::walk_crate(cx, krate);
+ });
+
+ // Put the lint store back in the session.
+ mem::replace(&mut *sess.lint_store.borrow_mut(), cx.lints);
+
+ // If we missed any lints added to the session, then there's a bug somewhere
+ // in the iteration code.
+ for (_, v) in sess.lints.borrow().iter() {
+ for &(lint, span, ref msg) in v {
+ sess.span_bug(span,
+ &format!("unprocessed lint {}: {}",
+ lint.as_str(), *msg))
+ }
+ }
+}
use std::ascii::AsciiExt;
use syntax::codemap::Span;
use rustc_front::visit::FnKind;
+use syntax::visit as ast_visit;
use syntax::ast;
use rustc_front::hir;
-pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_attrs,
- gather_attrs_from_hir, GatherNodeLevels};
+pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore,
+ raw_emit_lint, check_crate, check_ast_crate, gather_attrs,
+ GatherNodeLevels};
/// Specification of a single lint.
#[derive(Copy, Clone, Debug)]
/// Declare a static item of type `&'static Lint`.
#[macro_export]
macro_rules! declare_lint {
- // FIXME(#14660): deduplicate
(pub $name:ident, $level:ident, $desc:expr) => (
pub static $name: &'static ::rustc::lint::Lint
= &lint_initializer!($name, $level, $desc);
pub type LintArray = &'static [&'static &'static Lint];
-/// Trait for types providing lint checks.
-///
-/// Each `check` method checks a single syntax node, and should not
-/// invoke methods recursively (unlike `Visitor`). By default they
-/// do nothing.
-//
-// FIXME: eliminate the duplication with `Visitor`. But this also
-// contains a few lint-specific methods with no equivalent in `Visitor`.
pub trait LintPass {
/// Get descriptions of the lints this `LintPass` object can emit.
///
/// parts of the compiler. If you want enforced access restrictions for your
/// `Lint`, make it a private `static` item in its own module.
fn get_lints(&self) -> LintArray;
+}
+
- fn check_crate(&mut self, _: &Context, _: &hir::Crate) { }
- fn check_ident(&mut self, _: &Context, _: Span, _: ast::Ident) { }
- fn check_mod(&mut self, _: &Context, _: &hir::Mod, _: Span, _: ast::NodeId) { }
- fn check_foreign_item(&mut self, _: &Context, _: &hir::ForeignItem) { }
- fn check_item(&mut self, _: &Context, _: &hir::Item) { }
- fn check_local(&mut self, _: &Context, _: &hir::Local) { }
- fn check_block(&mut self, _: &Context, _: &hir::Block) { }
- fn check_stmt(&mut self, _: &Context, _: &hir::Stmt) { }
- fn check_arm(&mut self, _: &Context, _: &hir::Arm) { }
- fn check_pat(&mut self, _: &Context, _: &hir::Pat) { }
- fn check_decl(&mut self, _: &Context, _: &hir::Decl) { }
- fn check_expr(&mut self, _: &Context, _: &hir::Expr) { }
- fn check_expr_post(&mut self, _: &Context, _: &hir::Expr) { }
- fn check_ty(&mut self, _: &Context, _: &hir::Ty) { }
- fn check_generics(&mut self, _: &Context, _: &hir::Generics) { }
- fn check_fn(&mut self, _: &Context,
+/// Trait for types providing lint checks.
+///
+/// Each `check` method checks a single syntax node, and should not
+/// invoke methods recursively (unlike `Visitor`). By default they
+/// do nothing.
+//
+// FIXME: eliminate the duplication with `Visitor`. But this also
+// contains a few lint-specific methods with no equivalent in `Visitor`.
+pub trait LateLintPass: LintPass {
+ fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { }
+ fn check_crate(&mut self, _: &LateContext, _: &hir::Crate) { }
+ fn check_mod(&mut self, _: &LateContext, _: &hir::Mod, _: Span, _: ast::NodeId) { }
+ fn check_foreign_item(&mut self, _: &LateContext, _: &hir::ForeignItem) { }
+ fn check_item(&mut self, _: &LateContext, _: &hir::Item) { }
+ fn check_local(&mut self, _: &LateContext, _: &hir::Local) { }
+ fn check_block(&mut self, _: &LateContext, _: &hir::Block) { }
+ fn check_stmt(&mut self, _: &LateContext, _: &hir::Stmt) { }
+ fn check_arm(&mut self, _: &LateContext, _: &hir::Arm) { }
+ fn check_pat(&mut self, _: &LateContext, _: &hir::Pat) { }
+ fn check_decl(&mut self, _: &LateContext, _: &hir::Decl) { }
+ fn check_expr(&mut self, _: &LateContext, _: &hir::Expr) { }
+ fn check_expr_post(&mut self, _: &LateContext, _: &hir::Expr) { }
+ fn check_ty(&mut self, _: &LateContext, _: &hir::Ty) { }
+ fn check_generics(&mut self, _: &LateContext, _: &hir::Generics) { }
+ fn check_fn(&mut self, _: &LateContext,
_: FnKind, _: &hir::FnDecl, _: &hir::Block, _: Span, _: ast::NodeId) { }
- fn check_trait_item(&mut self, _: &Context, _: &hir::TraitItem) { }
- fn check_impl_item(&mut self, _: &Context, _: &hir::ImplItem) { }
- fn check_struct_def(&mut self, _: &Context,
- _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { }
- fn check_struct_def_post(&mut self, _: &Context,
- _: &hir::StructDef, _: ast::Ident, _: &hir::Generics, _: ast::NodeId) { }
- fn check_struct_field(&mut self, _: &Context, _: &hir::StructField) { }
- fn check_variant(&mut self, _: &Context, _: &hir::Variant, _: &hir::Generics) { }
- fn check_variant_post(&mut self, _: &Context, _: &hir::Variant, _: &hir::Generics) { }
- fn check_opt_lifetime_ref(&mut self, _: &Context, _: Span, _: &Option<hir::Lifetime>) { }
- fn check_lifetime_ref(&mut self, _: &Context, _: &hir::Lifetime) { }
- fn check_lifetime_def(&mut self, _: &Context, _: &hir::LifetimeDef) { }
- fn check_explicit_self(&mut self, _: &Context, _: &hir::ExplicitSelf) { }
- fn check_mac(&mut self, _: &Context, _: &ast::Mac) { }
- fn check_path(&mut self, _: &Context, _: &hir::Path, _: ast::NodeId) { }
- fn check_attribute(&mut self, _: &Context, _: &hir::Attribute) { }
+ fn check_trait_item(&mut self, _: &LateContext, _: &hir::TraitItem) { }
+ fn check_impl_item(&mut self, _: &LateContext, _: &hir::ImplItem) { }
+ fn check_struct_def(&mut self, _: &LateContext,
+ _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
+ fn check_struct_def_post(&mut self, _: &LateContext,
+ _: &hir::VariantData, _: ast::Name, _: &hir::Generics, _: ast::NodeId) { }
+ fn check_struct_field(&mut self, _: &LateContext, _: &hir::StructField) { }
+ fn check_variant(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
+ fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) { }
+ fn check_lifetime(&mut self, _: &LateContext, _: &hir::Lifetime) { }
+ fn check_lifetime_def(&mut self, _: &LateContext, _: &hir::LifetimeDef) { }
+ fn check_explicit_self(&mut self, _: &LateContext, _: &hir::ExplicitSelf) { }
+ fn check_path(&mut self, _: &LateContext, _: &hir::Path, _: ast::NodeId) { }
+ fn check_path_list_item(&mut self, _: &LateContext, _: &hir::PathListItem) { }
+ fn check_attribute(&mut self, _: &LateContext, _: &ast::Attribute) { }
+
+ /// Called when entering a syntax node that can have lint attributes such
+ /// as `#[allow(...)]`. Called with *all* the attributes of that node.
+ fn enter_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { }
+
+ /// Counterpart to `enter_lint_attrs`.
+ fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) { }
+}
+
+pub trait EarlyLintPass: LintPass {
+ fn check_ident(&mut self, _: &EarlyContext, _: Span, _: ast::Ident) { }
+ fn check_crate(&mut self, _: &EarlyContext, _: &ast::Crate) { }
+ fn check_mod(&mut self, _: &EarlyContext, _: &ast::Mod, _: Span, _: ast::NodeId) { }
+ fn check_foreign_item(&mut self, _: &EarlyContext, _: &ast::ForeignItem) { }
+ fn check_item(&mut self, _: &EarlyContext, _: &ast::Item) { }
+ fn check_local(&mut self, _: &EarlyContext, _: &ast::Local) { }
+ fn check_block(&mut self, _: &EarlyContext, _: &ast::Block) { }
+ fn check_stmt(&mut self, _: &EarlyContext, _: &ast::Stmt) { }
+ fn check_arm(&mut self, _: &EarlyContext, _: &ast::Arm) { }
+ fn check_pat(&mut self, _: &EarlyContext, _: &ast::Pat) { }
+ fn check_decl(&mut self, _: &EarlyContext, _: &ast::Decl) { }
+ fn check_expr(&mut self, _: &EarlyContext, _: &ast::Expr) { }
+ fn check_expr_post(&mut self, _: &EarlyContext, _: &ast::Expr) { }
+ fn check_ty(&mut self, _: &EarlyContext, _: &ast::Ty) { }
+ fn check_generics(&mut self, _: &EarlyContext, _: &ast::Generics) { }
+ fn check_fn(&mut self, _: &EarlyContext,
+ _: ast_visit::FnKind, _: &ast::FnDecl, _: &ast::Block, _: Span, _: ast::NodeId) { }
+ fn check_trait_item(&mut self, _: &EarlyContext, _: &ast::TraitItem) { }
+ fn check_impl_item(&mut self, _: &EarlyContext, _: &ast::ImplItem) { }
+ fn check_struct_def(&mut self, _: &EarlyContext,
+ _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
+ fn check_struct_def_post(&mut self, _: &EarlyContext,
+ _: &ast::VariantData, _: ast::Ident, _: &ast::Generics, _: ast::NodeId) { }
+ fn check_struct_field(&mut self, _: &EarlyContext, _: &ast::StructField) { }
+ fn check_variant(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
+ fn check_variant_post(&mut self, _: &EarlyContext, _: &ast::Variant, _: &ast::Generics) { }
+ fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { }
+ fn check_lifetime_def(&mut self, _: &EarlyContext, _: &ast::LifetimeDef) { }
+ fn check_explicit_self(&mut self, _: &EarlyContext, _: &ast::ExplicitSelf) { }
+ fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { }
+ fn check_path_list_item(&mut self, _: &EarlyContext, _: &ast::PathListItem) { }
+ fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { }
/// Called when entering a syntax node that can have lint attributes such
/// as `#[allow(...)]`. Called with *all* the attributes of that node.
- fn enter_lint_attrs(&mut self, _: &Context, _: &[hir::Attribute]) { }
+ fn enter_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }
/// Counterpart to `enter_lint_attrs`.
- fn exit_lint_attrs(&mut self, _: &Context, _: &[hir::Attribute]) { }
+ fn exit_lint_attrs(&mut self, _: &EarlyContext, _: &[ast::Attribute]) { }
}
/// A lint pass boxed up as a trait object.
-pub type LintPassObject = Box<LintPass + 'static>;
+pub type EarlyLintPassObject = Box<EarlyLintPass + 'static>;
+pub type LateLintPassObject = Box<LateLintPass + 'static>;
/// Identifies a lint known to the compiler.
#[derive(Clone, Copy)]
pub const tag_items_data_item_is_tuple_struct_ctor: usize = 0x29;
-pub const tag_index: usize = 0x2a;
+pub const tag_items_closure_kind: usize = 0x2a;
+pub const tag_items_closure_ty: usize = 0x2b;
+pub const tag_def_key: usize = 0x2c;
-// GAP 0x2b, 0x2c, 0x2d, 0x2e
+// GAP 0x2d 0x2e
+
+pub const tag_index: usize = 0x110; // top-level only
+pub const tag_xref_index: usize = 0x111; // top-level only
+pub const tag_xref_data: usize = 0x112; // top-level only
pub const tag_meta_item_name_value: usize = 0x2f;
pub const tag_crate_dep_hash: usize = 0x37;
pub const tag_crate_dep_explicitly_linked: usize = 0x38; // top-level only
-pub const tag_mod_impl: usize = 0x39;
-
pub const tag_item_trait_item: usize = 0x3a;
pub const tag_item_trait_ref: usize = 0x3b;
pub const tag_path_elem_mod: usize = 0x3f;
pub const tag_path_elem_name: usize = 0x40;
pub const tag_item_field: usize = 0x41;
-pub const tag_item_field_origin: usize = 0x42;
pub const tag_item_variances: usize = 0x43;
/*
tag_tree = 0x51,
- tag_id_range = 0x52,
-
+ // GAP 0x52
tag_table = 0x53,
// GAP 0x54, 0x55
tag_table_def = 0x56,
tag_table_node_type = 0x57,
tag_table_item_subst = 0x58,
tag_table_freevars = 0x59,
- tag_table_tcache = 0x5a,
- tag_table_param_defs = 0x5b,
- tag_table_mutbl = 0x5c,
- tag_table_last_use = 0x5d,
- tag_table_spill = 0x5e,
+ // GAP 0x5a, 0x5b, 0x5c, 0x5d, 0x5e
tag_table_method_map = 0x5f,
- tag_table_vtable_map = 0x60,
+ // GAP 0x60
tag_table_adjustments = 0x61,
- tag_table_moves_map = 0x62,
- tag_table_capture_map = 0x63,
- tag_table_closure_tys = 0x64,
- tag_table_closure_kinds = 0x65,
+ // GAP 0x62, 0x63, 0x64, 0x65
tag_table_upvar_capture_map = 0x66,
- tag_table_capture_modes = 0x67,
- // GAP 0x68
+ // GAP 0x67, 0x68
tag_table_const_qualif = 0x69,
tag_table_cast_kinds = 0x6a,
}
pub const tag_item_trait_item_sort: usize = 0x70;
-pub const tag_item_trait_parent_sort: usize = 0x71;
-
-pub const tag_item_impl_type_basename: usize = 0x72;
-
pub const tag_crate_triple: usize = 0x105; // top-level only
pub const tag_dylib_dependency_formats: usize = 0x106; // top-level only
// tag_lang_items
// - tag_lang_items_item
// - tag_lang_items_item_id: u32
-// - tag_lang_items_item_node_id: u32
+// - tag_lang_items_item_index: u32
pub const tag_lang_items: usize = 0x107; // top-level only
pub const tag_lang_items_item: usize = 0x73;
pub const tag_lang_items_item_id: usize = 0x74;
-pub const tag_lang_items_item_node_id: usize = 0x75;
+pub const tag_lang_items_item_index: usize = 0x75;
pub const tag_lang_items_missing: usize = 0x76;
pub const tag_item_unnamed_field: usize = 0x77;
pub const tag_items_data_item_visibility: usize = 0x78;
-
-pub const tag_item_method_tps: usize = 0x79;
-pub const tag_item_method_fty: usize = 0x7a;
-
+pub const tag_items_data_item_inherent_impl: usize = 0x79;
+// GAP 0x7a
pub const tag_mod_child: usize = 0x7b;
pub const tag_misc_info: usize = 0x108; // top-level only
pub const tag_misc_info_crate_items: usize = 0x7c;
-pub const tag_item_method_provided_source: usize = 0x7d;
-pub const tag_item_impl_vtables: usize = 0x7e;
-
pub const tag_impls: usize = 0x109; // top-level only
-pub const tag_impls_impl: usize = 0x7f;
-pub const tag_impls_impl_trait_def_id: usize = 0x8d;
+pub const tag_impls_trait: usize = 0x7d;
+pub const tag_impls_trait_impl: usize = 0x7e;
-pub const tag_items_data_item_inherent_impl: usize = 0x80;
-pub const tag_items_data_item_extension_impl: usize = 0x81;
+// GAP 0x7f, 0x80, 0x81
pub const tag_native_libraries: usize = 0x10a; // top-level only
pub const tag_native_libraries_lib: usize = 0x82;
pub const tag_struct_fields: usize = 0x10d; // top-level only
pub const tag_struct_field: usize = 0x8a;
-pub const tag_struct_field_id: usize = 0x8b;
+pub const tag_items_data_item_struct_ctor: usize = 0x8b;
pub const tag_attribute_is_sugared_doc: usize = 0x8c;
-
+// GAP 0x8d
pub const tag_items_data_region: usize = 0x8e;
pub const tag_region_param_def: usize = 0x8f;
pub const tag_item_generics: usize = 0x95;
pub const tag_method_ty_generics: usize = 0x96;
-pub const tag_predicate: usize = 0x97;
-pub const tag_predicate_space: usize = 0x98;
-pub const tag_predicate_data: usize = 0x99;
+pub const tag_type_predicate: usize = 0x97;
+pub const tag_self_predicate: usize = 0x98;
+pub const tag_fn_predicate: usize = 0x99;
pub const tag_unsafety: usize = 0x9a;
pub const tag_impl_coerce_unsized_kind: usize = 0xa5;
pub const tag_items_data_item_constness: usize = 0xa6;
+
+pub const tag_rustc_version: usize = 0x10f;
+pub fn rustc_version() -> String {
+ format!(
+ "rustc {}",
+ option_env!("CFG_VERSION").unwrap_or("unknown version")
+ )
+}
use back::svh::Svh;
use session::{config, Session};
use session::search_paths::PathKind;
+use metadata::common::rustc_version;
use metadata::cstore;
use metadata::cstore::{CStore, CrateSource, MetadataBlob};
use metadata::decoder;
use syntax::codemap::{self, Span, mk_sp, Pos};
use syntax::parse;
use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::parse::token::InternedString;
use syntax::util::small_vector::SmallVector;
use rustc_front::visit;
use rustc_front::hir;
-use rustc_front::attr as attr_front;
-use rustc_front::attr::AttrMetaMethods;
-use rustc_front::lowering::unlower_attribute;
use log;
pub struct LocalCrateReader<'a, 'b:'a> {
fn should_link(i: &ast::Item) -> bool {
!attr::contains_name(&i.attrs, "no_link")
}
-
// Dup for the hir
fn should_link_hir(i: &hir::Item) -> bool {
- !attr_front::contains_name(&i.attrs, "no_link")
+ !attr::contains_name(&i.attrs, "no_link")
}
struct CrateInfo {
if name.is_empty() {
match span {
Some(span) => {
- sess.span_err(span, "#[link(name = \"\")] given with \
- empty name");
+ span_err!(sess, span, E0454,
+ "#[link(name = \"\")] given with empty name");
}
None => {
sess.err("empty library name given via `-l`");
if kind == cstore::NativeFramework && !is_osx {
let msg = "native frameworks are only available on OSX targets";
match span {
- Some(span) => sess.span_err(span, msg),
+ Some(span) => {
+ span_err!(sess, span, E0455,
+ "{}", msg)
+ }
None => sess.err(msg),
}
}
match i.node {
hir::ItemExternCrate(ref path_opt) => {
debug!("resolving extern crate stmt. ident: {} path_opt: {:?}",
- i.ident, path_opt);
+ i.name, path_opt);
let name = match *path_opt {
Some(name) => {
validate_crate_name(Some(self.sess), &name.as_str(),
Some(i.span));
name.to_string()
}
- None => i.ident.to_string(),
+ None => i.name.to_string(),
};
Some(CrateInfo {
- ident: i.ident.to_string(),
+ ident: i.name.to_string(),
name: name,
id: i.id,
should_link: should_link_hir(i),
return ret;
}
+ fn verify_rustc_version(&self,
+ name: &str,
+ span: Span,
+ metadata: &MetadataBlob) {
+ let crate_rustc_version = decoder::crate_rustc_version(metadata.as_slice());
+ if crate_rustc_version != Some(rustc_version()) {
+ span_err!(self.sess, span, E0514,
+ "the crate `{}` has been compiled with {}, which is \
+ incompatible with this version of rustc",
+ name,
+ crate_rustc_version
+ .as_ref().map(|s|&**s)
+ .unwrap_or("an old version of rustc")
+ );
+ self.sess.abort_if_errors();
+ }
+ }
+
fn register_crate(&mut self,
root: &Option<CratePaths>,
ident: &str,
explicitly_linked: bool)
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
+ self.verify_rustc_version(name, span, &lib.metadata);
+
// Claim this crate number and cache it
let cnum = self.next_crate_num;
self.next_crate_num += 1;
let cmeta = Rc::new(cstore::crate_metadata {
name: name.to_string(),
local_path: RefCell::new(SmallVector::zero()),
+ local_def_path: RefCell::new(vec![]),
index: decoder::load_index(metadata.as_slice()),
+ xref_index: decoder::load_xrefs(metadata.as_slice()),
data: metadata,
cnum_map: RefCell::new(cnum_map),
cnum: cnum,
let attrs = decoder::get_crate_attributes(data);
for attr in &attrs {
if &attr.name()[..] == "staged_api" {
- match attr.node.value.node { hir::MetaWord(_) => return true, _ => (/*pass*/) }
+ match attr.node.value.node { ast::MetaWord(_) => return true, _ => (/*pass*/) }
}
}
};
let span = mk_sp(lo, p.last_span.hi);
p.abort_if_errors();
+
+ // Mark the attrs as used
+ for attr in &attrs {
+ attr::mark_used(attr);
+ }
+
macros.push(ast::MacroDef {
- ident: name.ident(),
- attrs: attrs.iter().map(|a| unlower_attribute(a)).collect(),
+ ident: ast::Ident::with_empty_ctxt(name),
+ attrs: attrs,
id: ast::DUMMY_NODE_ID,
span: span,
imported_from: Some(item.ident),
name,
config::host_triple(),
self.sess.opts.target_triple);
- self.sess.span_err(span, &message[..]);
+ span_err!(self.sess, span, E0456, "{}", &message[..]);
self.sess.abort_if_errors();
}
- let registrar = decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
+ let registrar =
+ decoder::get_plugin_registrar_fn(ekrate.metadata.as_slice())
.map(|id| decoder::get_symbol_from_buf(ekrate.metadata.as_slice(), id));
match (ekrate.dylib.as_ref(), registrar) {
(Some(dylib), Some(reg)) => Some((dylib.to_path_buf(), reg)),
(None, Some(_)) => {
- let message = format!("plugin `{}` only found in rlib format, \
- but must be available in dylib format",
- name);
- self.sess.span_err(span, &message[..]);
+ span_err!(self.sess, span, E0457,
+ "plugin `{}` only found in rlib format, but must be available \
+ in dylib format",
+ name);
// No need to abort because the loading code will just ignore this
// empty dylib.
None
i.span,
PathKind::Crate,
true);
+ let def_id = self.ast_map.local_def_id(i.id);
+ let def_path = self.ast_map.def_path(def_id);
+ cmeta.update_local_def_path(def_path);
self.ast_map.with_path(i.id, |path| {
cmeta.update_local_path(path)
});
Some("dylib") => cstore::NativeUnknown,
Some("framework") => cstore::NativeFramework,
Some(k) => {
- self.sess.span_err(m.span, &format!("unknown kind: `{}`", k));
+ span_err!(self.sess, m.span, E0458,
+ "unknown kind: `{}`", k);
cstore::NativeUnknown
}
None => cstore::NativeUnknown
let n = match n {
Some(n) => n,
None => {
- self.sess.span_err(m.span, "#[link(...)] specified without \
- `name = \"foo\"`");
+ span_err!(self.sess, m.span, E0459,
+ "#[link(...)] specified without `name = \"foo\"`");
InternedString::new("foo")
}
};
use metadata::cstore;
use metadata::decoder;
use metadata::inline::InlinedItem;
-use middle::def_id::DefId;
+use middle::def_id::{DefId, DefIndex};
use middle::lang_items;
use middle::ty;
use util::nodemap::FnvHashMap;
use std::rc::Rc;
use syntax::ast;
-use rustc_front::attr;
+use syntax::attr;
use rustc_front::hir;
#[derive(Copy, Clone)]
pub fn get_symbol(cstore: &cstore::CStore, def: DefId) -> String {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_symbol(&cdata, def.node)
+ decoder::get_symbol(&cdata, def.index)
}
/// Iterates over all the language items in the given crate.
cnum: ast::CrateNum,
f: F)
-> bool where
- F: FnMut(ast::NodeId, usize) -> bool,
+ F: FnMut(DefIndex, usize) -> bool,
{
let crate_data = cstore.get_crate_data(cnum);
decoder::each_lang_item(&*crate_data, f)
};
decoder::each_child_of_item(cstore.intr.clone(),
&*crate_data,
- def_id.node,
+ def_id.index,
get_crate_data,
callback)
}
pub fn get_item_path(tcx: &ty::ctxt, def: DefId) -> Vec<ast_map::PathElem> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- let path = decoder::get_item_path(&*cdata, def.node);
+ let path = decoder::get_item_path(&*cdata, def.index);
cdata.with_local_path(|cpath| {
let mut r = Vec::with_capacity(cpath.len() + path.len());
pub fn get_item_name(tcx: &ty::ctxt, def: DefId) -> ast::Name {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_item_name(&cstore.intr, &cdata, def.node)
+ decoder::get_item_name(&cstore.intr, &cdata, def.index)
}
pub enum FoundAst<'ast> {
-> FoundAst<'tcx> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::maybe_get_item_ast(&*cdata, tcx, def.node, decode_inlined_item)
+ decoder::maybe_get_item_ast(&*cdata, tcx, def.index, decode_inlined_item)
}
/// Returns information about the given implementation.
pub fn get_impl_items(cstore: &cstore::CStore, impl_def_id: DefId)
-> Vec<ty::ImplOrTraitItemId> {
let cdata = cstore.get_crate_data(impl_def_id.krate);
- decoder::get_impl_items(&*cdata, impl_def_id.node)
+ decoder::get_impl_items(&*cdata, impl_def_id.index)
}
pub fn get_impl_or_trait_item<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
let cdata = tcx.sess.cstore.get_crate_data(def.krate);
decoder::get_impl_or_trait_item(tcx.sess.cstore.intr.clone(),
&*cdata,
- def.node,
+ def.index,
tcx)
}
let cdata = cstore.get_crate_data(def.krate);
decoder::get_trait_name(cstore.intr.clone(),
&*cdata,
- def.node)
+ def.index)
}
pub fn is_static_method(cstore: &cstore::CStore, def: DefId) -> bool {
let cdata = cstore.get_crate_data(def.krate);
- decoder::is_static_method(&*cdata, def.node)
+ decoder::is_static_method(&*cdata, def.index)
}
pub fn get_trait_item_def_ids(cstore: &cstore::CStore, def: DefId)
-> Vec<ty::ImplOrTraitItemId> {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_trait_item_def_ids(&*cdata, def.node)
+ decoder::get_trait_item_def_ids(&*cdata, def.index)
}
pub fn get_item_variances(cstore: &cstore::CStore,
def: DefId) -> ty::ItemVariances {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_item_variances(&*cdata, def.node)
+ decoder::get_item_variances(&*cdata, def.index)
}
pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
-> Vec<Rc<ty::Method<'tcx>>> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
+ decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.index, tcx)
}
pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx)
-}
-
-pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: DefId)
- -> Option<ast::Name> {
- let cdata = cstore.get_crate_data(def.krate);
- decoder::get_type_name_if_impl(&*cdata, def.node)
+ decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.index, tcx)
}
pub fn get_methods_if_impl(cstore: &cstore::CStore,
def: DefId)
-> Option<Vec<MethodInfo> > {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.node)
+ decoder::get_methods_if_impl(cstore.intr.clone(), &*cdata, def.index)
}
pub fn get_item_attrs(cstore: &cstore::CStore,
def_id: DefId)
- -> Vec<hir::Attribute> {
+ -> Vec<ast::Attribute> {
let cdata = cstore.get_crate_data(def_id.krate);
- decoder::get_item_attrs(&*cdata, def_id.node)
+ decoder::get_item_attrs(&*cdata, def_id.index)
}
pub fn get_struct_field_names(cstore: &cstore::CStore, def: DefId) -> Vec<ast::Name> {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_struct_field_names(&cstore.intr, &*cdata, def.node)
+ decoder::get_struct_field_names(&cstore.intr, &*cdata, def.index)
}
-pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: DefId) -> FnvHashMap<ast::NodeId,
- Vec<hir::Attribute>> {
+pub fn get_struct_field_attrs(cstore: &cstore::CStore, def: DefId)
+ -> FnvHashMap<DefId, Vec<ast::Attribute>> {
let cdata = cstore.get_crate_data(def.krate);
decoder::get_struct_field_attrs(&*cdata)
}
-> ty::TypeScheme<'tcx> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_type(&*cdata, def.node, tcx)
+ decoder::get_type(&*cdata, def.index, tcx)
}
pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::TraitDef<'tcx> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_trait_def(&*cdata, def.node, tcx)
+ decoder::get_trait_def(&*cdata, def.index, tcx)
}
pub fn get_adt_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_adt_def(&cstore.intr, &*cdata, def.node, tcx)
+ decoder::get_adt_def(&cstore.intr, &*cdata, def.index, tcx)
}
pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
{
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_predicates(&*cdata, def.node, tcx)
+ decoder::get_predicates(&*cdata, def.index, tcx)
}
pub fn get_super_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: DefId)
{
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_super_predicates(&*cdata, def.node, tcx)
+ decoder::get_super_predicates(&*cdata, def.index, tcx)
}
pub fn get_impl_polarity<'tcx>(tcx: &ty::ctxt<'tcx>,
{
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_impl_polarity(&*cdata, def.node)
+ decoder::get_impl_polarity(&*cdata, def.index)
}
pub fn get_custom_coerce_unsized_kind<'tcx>(
{
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_custom_coerce_unsized_kind(&*cdata, def.node)
+ decoder::get_custom_coerce_unsized_kind(&*cdata, def.index)
}
// Given a def_id for an impl, return the trait it implements,
-> Option<ty::TraitRef<'tcx>> {
let cstore = &tcx.sess.cstore;
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_impl_trait(&*cdata, def.node, tcx)
+ decoder::get_impl_trait(&*cdata, def.index, tcx)
}
pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum)
F: FnMut(DefId),
{
let cdata = cstore.get_crate_data(def_id.krate);
- decoder::each_inherent_implementation_for_type(&*cdata, def_id.node, callback)
+ decoder::each_inherent_implementation_for_type(&*cdata, def_id.index, callback)
}
pub fn each_implementation_for_trait<F>(cstore: &cstore::CStore,
tcx: &ty::ctxt)
-> Option<DefId> {
let cdata = cstore.get_crate_data(def_id.krate);
- decoder::get_trait_of_item(&*cdata, def_id.node, tcx)
+ decoder::get_trait_of_item(&*cdata, def_id.index, tcx)
}
pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore,
-> Option<DefId>
{
let cdata = cstore.get_crate_data(def_id.krate);
- decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.node)
+ decoder::get_tuple_struct_definition_if_ctor(&*cdata, def_id.index)
}
pub fn get_dylib_dependency_formats(cstore: &cstore::CStore,
-> Vec<String>
{
let cdata = cstore.get_crate_data(did.krate);
- decoder::get_method_arg_names(&*cdata, did.node)
+ decoder::get_method_arg_names(&*cdata, did.index)
}
pub fn get_reachable_ids(cstore: &cstore::CStore, cnum: ast::CrateNum)
pub fn is_typedef(cstore: &cstore::CStore, did: DefId) -> bool {
let cdata = cstore.get_crate_data(did.krate);
- decoder::is_typedef(&*cdata, did.node)
+ decoder::is_typedef(&*cdata, did.index)
}
pub fn is_const_fn(cstore: &cstore::CStore, did: DefId) -> bool {
let cdata = cstore.get_crate_data(did.krate);
- decoder::is_const_fn(&*cdata, did.node)
+ decoder::is_const_fn(&*cdata, did.index)
}
pub fn is_impl(cstore: &cstore::CStore, did: DefId) -> bool {
let cdata = cstore.get_crate_data(did.krate);
- decoder::is_impl(&*cdata, did.node)
+ decoder::is_impl(&*cdata, did.index)
}
pub fn get_stability(cstore: &cstore::CStore,
def: DefId)
-> Option<attr::Stability> {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_stability(&*cdata, def.node)
+ decoder::get_stability(&*cdata, def.index)
}
pub fn is_staged_api(cstore: &cstore::CStore, krate: ast::CrateNum) -> bool {
pub fn get_repr_attrs(cstore: &cstore::CStore, def: DefId)
-> Vec<attr::ReprAttr> {
let cdata = cstore.get_crate_data(def.krate);
- decoder::get_repr_attrs(&*cdata, def.node)
+ decoder::get_repr_attrs(&*cdata, def.index)
}
pub fn is_defaulted_trait(cstore: &cstore::CStore, trait_def_id: DefId) -> bool {
let cdata = cstore.get_crate_data(trait_def_id.krate);
- decoder::is_defaulted_trait(&*cdata, trait_def_id.node)
+ decoder::is_defaulted_trait(&*cdata, trait_def_id.index)
}
pub fn is_default_impl(cstore: &cstore::CStore, impl_did: DefId) -> bool {
let cdata = cstore.get_crate_data(impl_did.krate);
- decoder::is_default_impl(&*cdata, impl_did.node)
+ decoder::is_default_impl(&*cdata, impl_did.index)
}
pub fn is_extern_fn(cstore: &cstore::CStore, did: DefId,
tcx: &ty::ctxt) -> bool {
let cdata = cstore.get_crate_data(did.krate);
- decoder::is_extern_fn(&*cdata, did.node, tcx)
+ decoder::is_extern_fn(&*cdata, did.index, tcx)
+}
+
+pub fn closure_kind<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureKind {
+ assert!(!def_id.is_local());
+ let cdata = tcx.sess.cstore.get_crate_data(def_id.krate);
+ decoder::closure_kind(&*cdata, def_id.index)
+}
+
+pub fn closure_ty<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
+ assert!(!def_id.is_local());
+ let cdata = tcx.sess.cstore.get_crate_data(def_id.krate);
+ decoder::closure_ty(&*cdata, def_id.index, tcx)
+}
+
+pub fn def_path(tcx: &ty::ctxt, def: DefId) -> ast_map::DefPath {
+ let cstore = &tcx.sess.cstore;
+ let cdata = cstore.get_crate_data(def.krate);
+ let path = decoder::def_path(&*cdata, def.index);
+ let local_path = cdata.local_def_path();
+ local_path.into_iter().chain(path).collect()
}
+
use std::path::PathBuf;
use flate::Bytes;
use syntax::ast;
-use rustc_front::attr;
+use syntax::attr;
use syntax::codemap;
use syntax::parse::token;
use syntax::parse::token::IdentInterner;
pub struct crate_metadata {
pub name: String,
pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
+ pub local_def_path: RefCell<ast_map::DefPath>,
pub data: MetadataBlob,
pub cnum_map: RefCell<cnum_map>,
pub cnum: ast::CrateNum,
pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
pub span: codemap::Span,
pub staged_api: bool,
+
pub index: index::Index,
+ pub xref_index: index::DenseIndex,
/// Flag if this crate is required by an rlib version of this crate, or in
/// other words whether it was explicitly linked to. An example of a crate
pub intr: Rc<IdentInterner>,
}
+/// Item definitions in the currently-compiled crate would have the CrateNum
+/// LOCAL_CRATE in their DefId.
+pub const LOCAL_CRATE: ast::CrateNum = 0;
+
impl CStore {
pub fn new(intr: Rc<IdentInterner>) -> CStore {
CStore {
visit(cstore, dep, ordering);
}
ordering.push(cnum);
- };
+ }
for (&num, _) in self.metas.borrow().iter() {
visit(self, num, &mut ordering);
}
}
}
+ pub fn local_def_path(&self) -> ast_map::DefPath {
+ let local_def_path = self.local_def_path.borrow();
+ if local_def_path.is_empty() {
+ let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name));
+ vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }]
+ } else {
+ local_def_path.clone()
+ }
+ }
+
+ pub fn update_local_def_path(&self, candidate: ast_map::DefPath) {
+ let mut local_def_path = self.local_def_path.borrow_mut();
+ if local_def_path.is_empty() || candidate.len() < local_def_path.len() {
+ *local_def_path = candidate;
+ }
+ }
+
pub fn is_allocator(&self) -> bool {
let attrs = decoder::get_crate_attributes(self.data());
attr::contains_name(&attrs, "allocator")
pub use self::DefLike::*;
use self::Family::*;
-use front::map as ast_map;
-use rustc_front::print::pprust;
+use front::map as hir_map;
use rustc_front::hir;
use back::svh::Svh;
use metadata::cstore::crate_metadata;
+use metadata::cstore::LOCAL_CRATE;
use metadata::common::*;
use metadata::csearch::MethodInfo;
use metadata::csearch;
use metadata::inline::InlinedItem;
use metadata::tydecode::TyDecoder;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::{DefId, DefIndex};
use middle::lang_items;
use middle::subst;
use middle::ty::{ImplContainer, TraitContainer};
use rbml::reader;
use rbml;
use serialize::Decodable;
-use rustc_front::attr;
+use syntax::attr;
use syntax::parse::token::{IdentInterner, special_idents};
use syntax::parse::token;
use syntax::ast;
use syntax::abi;
use syntax::codemap;
+use syntax::print::pprust;
use syntax::ptr::P;
pub type Cmd<'a> = &'a crate_metadata;
impl crate_metadata {
- fn get_item(&self, item_id: ast::NodeId) -> Option<rbml::Doc> {
+ fn get_item(&self, item_id: DefIndex) -> Option<rbml::Doc> {
self.index.lookup_item(self.data(), item_id).map(|pos| {
reader::doc_at(self.data(), pos as usize).unwrap().doc
})
}
- fn lookup_item(&self, item_id: ast::NodeId) -> rbml::Doc {
+ fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc {
match self.get_item(item_id) {
- None => panic!("lookup_item: id not found: {}", item_id),
+ None => panic!("lookup_item: id not found: {:?}", item_id),
Some(d) => d
}
}
pub fn load_index(data: &[u8]) -> index::Index {
let index = reader::get_doc(rbml::Doc::new(data), tag_index);
- index::Index::from_buf(index.data, index.start, index.end)
+ index::Index::from_rbml(index)
+}
+
+pub fn crate_rustc_version(data: &[u8]) -> Option<String> {
+ let doc = rbml::Doc::new(data);
+ reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str())
+}
+
+pub fn load_xrefs(data: &[u8]) -> index::DenseIndex {
+ let index = reader::get_doc(rbml::Doc::new(data), tag_xref_index);
+ index::DenseIndex::from_buf(index.data, index.start, index.end)
}
#[derive(Debug, PartialEq)]
fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
let id = reader::doc_as_u64(d);
- let def_id = DefId { krate: (id >> 32) as u32, node: id as u32 };
+ let index = DefIndex::new((id & 0xFFFF_FFFF) as usize);
+ let def_id = DefId { krate: (id >> 32) as u32, index: index };
translate_def_id(cdata, def_id)
}
translated_def_id(cdata, reader::get_doc(d, tag_def_id))
}
-fn get_provided_source(d: rbml::Doc, cdata: Cmd) -> Option<DefId> {
- reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| {
- translated_def_id(cdata, doc)
- })
-}
-
fn reexports<'a>(d: rbml::Doc<'a>) -> reader::TaggedDocsIterator<'a> {
reader::tagged_docs(d, tag_items_data_item_reexport)
}
fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> {
let tp = reader::get_doc(doc, tag_items_data_item_type);
TyDecoder::with_doc(tcx, cdata.cnum, tp,
- &mut |_, did| translate_def_id(cdata, did))
+ &mut |did| translate_def_id(cdata, did))
.parse_ty()
}
fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option<Ty<'tcx>> {
reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
TyDecoder::with_doc(tcx, cdata.cnum, tp,
- &mut |_, did| translate_def_id(cdata, did))
+ &mut |did| translate_def_id(cdata, did))
.parse_ty()
})
}
-fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>,
- cdata: Cmd) -> ty::BareFnTy<'tcx> {
- let tp = reader::get_doc(doc, tag_item_method_fty);
- TyDecoder::with_doc(tcx, cdata.cnum, tp,
- &mut |_, did| translate_def_id(cdata, did))
- .parse_bare_fn_ty()
-}
-
pub fn item_type<'tcx>(_item_id: DefId, item: rbml::Doc,
tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx> {
doc_type(item, tcx, cdata)
fn doc_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
-> ty::TraitRef<'tcx> {
TyDecoder::with_doc(tcx, cdata.cnum, doc,
- &mut |_, did| translate_def_id(cdata, did))
+ &mut |did| translate_def_id(cdata, did))
.parse_trait_ref()
}
doc_trait_ref(tp, tcx, cdata)
}
-fn item_path(item_doc: rbml::Doc) -> Vec<ast_map::PathElem> {
+fn item_path(item_doc: rbml::Doc) -> Vec<hir_map::PathElem> {
let path_doc = reader::get_doc(item_doc, tag_path);
reader::docs(path_doc).filter_map(|(tag, elt_doc)| {
if tag == tag_path_elem_mod {
let s = elt_doc.as_str_slice();
- Some(ast_map::PathMod(token::intern(s)))
+ Some(hir_map::PathMod(token::intern(s)))
} else if tag == tag_path_elem_name {
let s = elt_doc.as_str_slice();
- Some(ast_map::PathName(token::intern(s)))
+ Some(hir_map::PathName(token::intern(s)))
} else {
// ignore tag_path_len element
None
match fam {
Constant => {
// Check whether we have an associated const item.
- if item_sort(item) == Some('C') {
- DlDef(def::DefAssociatedConst(did))
- } else {
- // Regular const item.
- DlDef(def::DefConst(did))
+ match item_sort(item) {
+ Some('C') | Some('c') => {
+ DlDef(def::DefAssociatedConst(did))
+ }
+ _ => {
+ // Regular const item.
+ DlDef(def::DefConst(did))
+ }
}
}
ImmStatic => DlDef(def::DefStatic(did, false)),
}
pub fn get_trait_def<'tcx>(cdata: Cmd,
- item_id: ast::NodeId,
+ item_id: DefIndex,
tcx: &ty::ctxt<'tcx>) -> ty::TraitDef<'tcx>
{
let item_doc = cdata.lookup_item(item_id);
pub fn get_adt_def<'tcx>(intr: &IdentInterner,
cdata: Cmd,
- item_id: ast::NodeId,
+ item_id: DefIndex,
tcx: &ty::ctxt<'tcx>) -> ty::AdtDefMaster<'tcx>
{
fn get_enum_variants<'tcx>(intr: &IdentInterner,
let mut disr_val = 0;
reader::tagged_docs(doc, tag_items_data_item_variant).map(|p| {
let did = translated_def_id(cdata, p);
- let item = cdata.lookup_item(did.node);
+ let item = cdata.lookup_item(did.index);
if let Some(disr) = variant_disr_val(item) {
disr_val = disr;
}
let doc = cdata.lookup_item(item_id);
- let did = DefId { krate: cdata.cnum, node: item_id };
+ let did = DefId { krate: cdata.cnum, index: item_id };
let (kind, variants) = match item_family(doc) {
- Enum => (ty::AdtKind::Enum,
- get_enum_variants(intr, cdata, doc, tcx)),
- Struct => (ty::AdtKind::Struct,
- vec![get_struct_variant(intr, cdata, doc, did, tcx)]),
- _ => tcx.sess.bug("get_adt_def called on a non-ADT")
+ Enum => {
+ (ty::AdtKind::Enum,
+ get_enum_variants(intr, cdata, doc, tcx))
+ }
+ Struct => {
+ let ctor_did =
+ reader::maybe_get_doc(doc, tag_items_data_item_struct_ctor).
+ map_or(did, |ctor_doc| translated_def_id(cdata, ctor_doc));
+ (ty::AdtKind::Struct,
+ vec![get_struct_variant(intr, cdata, doc, ctor_did, tcx)])
+ }
+ _ => tcx.sess.bug(
+ &format!("get_adt_def called on a non-ADT {:?} - {:?}",
+ item_family(doc), did))
};
let adt = tcx.intern_adt_def(did, kind, variants);
// from the ctor.
debug!("evaluating the ctor-type of {:?}",
variant.name);
- let ctor_ty = get_type(cdata, variant.did.node, tcx).ty;
+ let ctor_ty = get_type(cdata, variant.did.index, tcx).ty;
debug!("evaluating the ctor-type of {:?}.. {:?}",
variant.name,
ctor_ty);
} else {
for field in &variant.fields {
debug!("evaluating the type of {:?}::{:?}", variant.name, field.name);
- let ty = get_type(cdata, field.did.node, tcx).ty;
+ let ty = get_type(cdata, field.did.index, tcx).ty;
field.fulfill_ty(ty);
debug!("evaluating the type of {:?}::{:?}: {:?}",
variant.name, field.name, ty);
}
pub fn get_predicates<'tcx>(cdata: Cmd,
- item_id: ast::NodeId,
+ item_id: DefIndex,
tcx: &ty::ctxt<'tcx>)
-> ty::GenericPredicates<'tcx>
{
}
pub fn get_super_predicates<'tcx>(cdata: Cmd,
- item_id: ast::NodeId,
+ item_id: DefIndex,
tcx: &ty::ctxt<'tcx>)
-> ty::GenericPredicates<'tcx>
{
doc_predicates(item_doc, tcx, cdata, tag_item_super_predicates)
}
-pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
+pub fn get_type<'tcx>(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt<'tcx>)
-> ty::TypeScheme<'tcx>
{
let item_doc = cdata.lookup_item(id);
- let t = item_type(DefId { krate: cdata.cnum, node: id }, item_doc, tcx,
+ let t = item_type(DefId { krate: cdata.cnum, index: id }, item_doc, tcx,
cdata);
let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
ty::TypeScheme {
}
}
-pub fn get_stability(cdata: Cmd, id: ast::NodeId) -> Option<attr::Stability> {
+pub fn get_stability(cdata: Cmd, id: DefIndex) -> Option<attr::Stability> {
let item = cdata.lookup_item(id);
reader::maybe_get_doc(item, tag_items_data_item_stability).map(|doc| {
let mut decoder = reader::Decoder::new(doc);
})
}
-pub fn get_repr_attrs(cdata: Cmd, id: ast::NodeId) -> Vec<attr::ReprAttr> {
+pub fn get_repr_attrs(cdata: Cmd, id: DefIndex) -> Vec<attr::ReprAttr> {
let item = cdata.lookup_item(id);
match reader::maybe_get_doc(item, tag_items_data_item_repr).map(|doc| {
let mut decoder = reader::Decoder::new(doc);
}
pub fn get_impl_polarity<'tcx>(cdata: Cmd,
- id: ast::NodeId)
+ id: DefIndex)
-> Option<hir::ImplPolarity>
{
let item_doc = cdata.lookup_item(id);
pub fn get_custom_coerce_unsized_kind<'tcx>(
cdata: Cmd,
- id: ast::NodeId)
+ id: DefIndex)
-> Option<ty::adjustment::CustomCoerceUnsized>
{
let item_doc = cdata.lookup_item(id);
}
pub fn get_impl_trait<'tcx>(cdata: Cmd,
- id: ast::NodeId,
+ id: DefIndex,
tcx: &ty::ctxt<'tcx>)
-> Option<ty::TraitRef<'tcx>>
{
}
}
-pub fn get_symbol(cdata: Cmd, id: ast::NodeId) -> String {
+pub fn get_symbol(cdata: Cmd, id: DefIndex) -> String {
return item_symbol(cdata.lookup_item(id));
}
/// If you have a crate_metadata, call get_symbol instead
-pub fn get_symbol_from_buf(data: &[u8], id: ast::NodeId) -> String {
+pub fn get_symbol_from_buf(data: &[u8], id: DefIndex) -> String {
let index = load_index(data);
let pos = index.lookup_item(data, id).unwrap();
let doc = reader::doc_at(data, pos as usize).unwrap().doc;
/// Iterates over the language items in the given crate.
pub fn each_lang_item<F>(cdata: Cmd, mut f: F) -> bool where
- F: FnMut(ast::NodeId, usize) -> bool,
+ F: FnMut(DefIndex, usize) -> bool,
{
let root = rbml::Doc::new(cdata.data());
let lang_items = reader::get_doc(root, tag_lang_items);
reader::tagged_docs(lang_items, tag_lang_items_item).all(|item_doc| {
let id_doc = reader::get_doc(item_doc, tag_lang_items_item_id);
let id = reader::doc_as_u32(id_doc) as usize;
- let node_id_doc = reader::get_doc(item_doc,
- tag_lang_items_item_node_id);
- let node_id = reader::doc_as_u32(node_id_doc) as ast::NodeId;
+ let index_doc = reader::get_doc(item_doc, tag_lang_items_item_index);
+ let index = DefIndex::from_u32(reader::doc_as_u32(index_doc));
- f(node_id, id)
+ f(index, id)
})
}
};
// Get the item.
- match crate_data.get_item(child_def_id.node) {
+ match crate_data.get_item(child_def_id.index) {
None => {}
Some(child_item_doc) => {
// Hand off the item to the callback.
for inherent_impl_def_id_doc in reader::tagged_docs(item_doc,
tag_items_data_item_inherent_impl) {
let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc, cdata);
- if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.node) {
+ if let Some(inherent_impl_doc) = cdata.get_item(inherent_impl_def_id.index) {
for impl_item_def_id_doc in reader::tagged_docs(inherent_impl_doc,
tag_item_impl_item) {
let impl_item_def_id = item_def_id(impl_item_def_id_doc,
cdata);
- if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.node) {
+ if let Some(impl_method_doc) = cdata.get_item(impl_item_def_id.index) {
if let StaticMethod = item_family(impl_method_doc) {
// Hand off the static method to the callback.
let static_method_name = item_name(&*intr, impl_method_doc);
};
// Get the item.
- if let Some(child_item_doc) = crate_data.get_item(child_def_id.node) {
+ if let Some(child_item_doc) = crate_data.get_item(child_def_id.index) {
// Hand off the item to the callback.
let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
// These items have a public visibility because they're part of
/// Iterates over each child of the given item.
pub fn each_child_of_item<F, G>(intr: Rc<IdentInterner>,
cdata: Cmd,
- id: ast::NodeId,
+ id: DefIndex,
get_crate_data: G,
callback: F) where
F: FnMut(DefLike, ast::Name, hir::Visibility),
callback)
}
-pub fn get_item_path(cdata: Cmd, id: ast::NodeId) -> Vec<ast_map::PathElem> {
+pub fn get_item_path(cdata: Cmd, id: DefIndex) -> Vec<hir_map::PathElem> {
item_path(cdata.lookup_item(id))
}
-pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId) -> ast::Name {
+pub fn get_item_name(intr: &IdentInterner, cdata: Cmd, id: DefIndex) -> ast::Name {
item_name(intr, cdata.lookup_item(id))
}
pub type DecodeInlinedItem<'a> =
Box<for<'tcx> FnMut(Cmd,
&ty::ctxt<'tcx>,
- Vec<ast_map::PathElem>,
- rbml::Doc)
- -> Result<&'tcx InlinedItem, Vec<ast_map::PathElem>> + 'a>;
-
-pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeId,
+ Vec<hir_map::PathElem>,
+ hir_map::DefPath,
+ rbml::Doc,
+ DefId)
+ -> Result<&'tcx InlinedItem, (Vec<hir_map::PathElem>,
+ hir_map::DefPath)> + 'a>;
+
+pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: DefIndex,
mut decode_inlined_item: DecodeInlinedItem)
-> csearch::FoundAst<'tcx> {
- debug!("Looking up item: {}", id);
+ debug!("Looking up item: {:?}", id);
let item_doc = cdata.lookup_item(id);
+ let item_did = item_def_id(item_doc, cdata);
let path = item_path(item_doc).split_last().unwrap().1.to_vec();
- match decode_inlined_item(cdata, tcx, path, item_doc) {
+ let def_path = def_path(cdata, id);
+ match decode_inlined_item(cdata, tcx, path, def_path, item_doc, item_did) {
Ok(ii) => csearch::FoundAst::Found(ii),
- Err(path) => {
+ Err((path, def_path)) => {
match item_parent_item(cdata, item_doc) {
Some(did) => {
- let parent_item = cdata.lookup_item(did.node);
- match decode_inlined_item(cdata, tcx, path, parent_item) {
+ let parent_item = cdata.lookup_item(did.index);
+ match decode_inlined_item(cdata, tcx, path, def_path, parent_item, did) {
Ok(ii) => csearch::FoundAst::FoundParent(did, ii),
Err(_) => csearch::FoundAst::NotFound
}
}
/// Returns the def IDs of all the items in the given implementation.
-pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
+pub fn get_impl_items(cdata: Cmd, impl_id: DefIndex)
-> Vec<ty::ImplOrTraitItemId> {
reader::tagged_docs(cdata.lookup_item(impl_id), tag_item_impl_item).map(|doc| {
let def_id = item_def_id(doc, cdata);
match item_sort(doc) {
- Some('C') => ty::ConstTraitItemId(def_id),
+ Some('C') | Some('c') => ty::ConstTraitItemId(def_id),
Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
Some('t') => ty::TypeTraitItemId(def_id),
_ => panic!("unknown impl item sort"),
pub fn get_trait_name(intr: Rc<IdentInterner>,
cdata: Cmd,
- id: ast::NodeId)
+ id: DefIndex)
-> ast::Name {
let doc = cdata.lookup_item(id);
item_name(&*intr, doc)
}
-pub fn is_static_method(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool {
let doc = cdata.lookup_item(id);
match item_sort(doc) {
Some('r') | Some('p') => {
pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
cdata: Cmd,
- id: ast::NodeId,
+ id: DefIndex,
tcx: &ty::ctxt<'tcx>)
-> ty::ImplOrTraitItem<'tcx> {
let item_doc = cdata.lookup_item(id);
let def_id = item_def_id(item_doc, cdata);
let container_id = item_require_parent_item(cdata, item_doc);
- let container_doc = cdata.lookup_item(container_id.node);
+ let container_doc = cdata.lookup_item(container_id.index);
let container = match item_family(container_doc) {
Trait => TraitContainer(container_id),
_ => ImplContainer(container_id),
let vis = item_visibility(item_doc);
match item_sort(item_doc) {
- Some('C') => {
+ sort @ Some('C') | sort @ Some('c') => {
let ty = doc_type(item_doc, tcx, cdata);
- let default = get_provided_source(item_doc, cdata);
ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
name: name,
ty: ty,
vis: vis,
def_id: def_id,
container: container,
- default: default,
+ has_value: sort == Some('C')
}))
}
Some('r') | Some('p') => {
let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
- let fty = doc_method_fty(item_doc, tcx, cdata);
+ let ity = tcx.lookup_item_type(def_id).ty;
+ let fty = match ity.sty {
+ ty::TyBareFn(_, fty) => fty.clone(),
+ _ => tcx.sess.bug(&format!(
+ "the type {:?} of the method {:?} is not a function?",
+ ity, name))
+ };
let explicit_self = get_explicit_self(item_doc);
- let provided_source = get_provided_source(item_doc, cdata);
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
generics,
explicit_self,
vis,
def_id,
- container,
- provided_source)))
+ container)))
}
Some('t') => {
let ty = maybe_doc_type(item_doc, tcx, cdata);
}
}
-pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
+pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex)
-> Vec<ty::ImplOrTraitItemId> {
let item = cdata.lookup_item(id);
reader::tagged_docs(item, tag_item_trait_item).map(|mth| {
let def_id = item_def_id(mth, cdata);
match item_sort(mth) {
- Some('C') => ty::ConstTraitItemId(def_id),
+ Some('C') | Some('c') => ty::ConstTraitItemId(def_id),
Some('r') | Some('p') => ty::MethodTraitItemId(def_id),
Some('t') => ty::TypeTraitItemId(def_id),
_ => panic!("unknown trait item sort"),
}).collect()
}
-pub fn get_item_variances(cdata: Cmd, id: ast::NodeId) -> ty::ItemVariances {
+pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances {
let item_doc = cdata.lookup_item(id);
let variance_doc = reader::get_doc(item_doc, tag_item_variances);
let mut decoder = reader::Decoder::new(variance_doc);
pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
cdata: Cmd,
- id: ast::NodeId,
+ id: DefIndex,
tcx: &ty::ctxt<'tcx>)
-> Vec<Rc<ty::Method<'tcx>>> {
let item = cdata.lookup_item(id);
reader::tagged_docs(item, tag_item_trait_item).filter_map(|mth_id| {
let did = item_def_id(mth_id, cdata);
- let mth = cdata.lookup_item(did.node);
+ let mth = cdata.lookup_item(did.index);
if item_sort(mth) == Some('p') {
let trait_item = get_impl_or_trait_item(intr.clone(),
cdata,
- did.node,
+ did.index,
tcx);
if let ty::MethodTraitItem(ref method) = trait_item {
Some((*method).clone())
pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
cdata: Cmd,
- id: ast::NodeId,
+ id: DefIndex,
tcx: &ty::ctxt<'tcx>)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
let item = cdata.lookup_item(id);
[tag_item_trait_item, tag_item_impl_item].iter().flat_map(|&tag| {
reader::tagged_docs(item, tag).filter_map(|ac_id| {
let did = item_def_id(ac_id, cdata);
- let ac_doc = cdata.lookup_item(did.node);
-
- if item_sort(ac_doc) == Some('C') {
- let trait_item = get_impl_or_trait_item(intr.clone(),
- cdata,
- did.node,
- tcx);
- if let ty::ConstTraitItem(ref ac) = trait_item {
- Some((*ac).clone())
- } else {
- None
+ let ac_doc = cdata.lookup_item(did.index);
+
+ match item_sort(ac_doc) {
+ Some('C') | Some('c') => {
+ let trait_item = get_impl_or_trait_item(intr.clone(),
+ cdata,
+ did.index,
+ tcx);
+ if let ty::ConstTraitItem(ref ac) = trait_item {
+ Some((*ac).clone())
+ } else {
+ None
+ }
}
- } else {
- None
+ _ => None
}
})
}).collect()
}
-pub fn get_type_name_if_impl(cdata: Cmd,
- node_id: ast::NodeId) -> Option<ast::Name> {
- let item = cdata.lookup_item(node_id);
- if item_family(item) != Impl {
- return None;
- }
-
- reader::tagged_docs(item, tag_item_impl_type_basename).nth(0).map(|doc| {
- token::intern(doc.as_str_slice())
- })
-}
-
pub fn get_methods_if_impl(intr: Rc<IdentInterner>,
cdata: Cmd,
- node_id: ast::NodeId)
+ node_id: DefIndex)
-> Option<Vec<MethodInfo> > {
let item = cdata.lookup_item(node_id);
if item_family(item) != Impl {
let mut impl_methods = Vec::new();
for impl_method_id in impl_method_ids {
- let impl_method_doc = cdata.lookup_item(impl_method_id.node);
+ let impl_method_doc = cdata.lookup_item(impl_method_id.index);
let family = item_family(impl_method_doc);
match family {
StaticMethod | Method => {
/// If node_id is the constructor of a tuple struct, retrieve the NodeId of
/// the actual type definition, otherwise, return None
pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
- node_id: ast::NodeId)
+ node_id: DefIndex)
-> Option<DefId>
{
let item = cdata.lookup_item(node_id);
}
pub fn get_item_attrs(cdata: Cmd,
- orig_node_id: ast::NodeId)
- -> Vec<hir::Attribute> {
+ orig_node_id: DefIndex)
+ -> Vec<ast::Attribute> {
// The attributes for a tuple struct are attached to the definition, not the ctor;
// we assume that someone passing in a tuple struct ctor is actually wanting to
// look at the definition
let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id);
- let node_id = node_id.map(|x| x.node).unwrap_or(orig_node_id);
+ let node_id = node_id.map(|x| x.index).unwrap_or(orig_node_id);
let item = cdata.lookup_item(node_id);
get_attributes(item)
}
-pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap<ast::NodeId, Vec<hir::Attribute>> {
+pub fn get_struct_field_attrs(cdata: Cmd) -> FnvHashMap<DefId, Vec<ast::Attribute>> {
let data = rbml::Doc::new(cdata.data());
let fields = reader::get_doc(data, tag_struct_fields);
reader::tagged_docs(fields, tag_struct_field).map(|field| {
- let id = reader::doc_as_u32(reader::get_doc(field, tag_struct_field_id));
+ let def_id = translated_def_id(cdata, reader::get_doc(field, tag_def_id));
let attrs = get_attributes(field);
- (id, attrs)
+ (def_id, attrs)
}).collect()
}
}
}
-pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: ast::NodeId)
+pub fn get_struct_field_names(intr: &IdentInterner, cdata: Cmd, id: DefIndex)
-> Vec<ast::Name> {
let item = cdata.lookup_item(id);
reader::tagged_docs(item, tag_item_field).map(|an_item| {
})).collect()
}
-fn get_meta_items(md: rbml::Doc) -> Vec<P<hir::MetaItem>> {
+fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
let n = token::intern_and_get_ident(nd.as_str_slice());
})).collect()
}
-fn get_attributes(md: rbml::Doc) -> Vec<hir::Attribute> {
+fn get_attributes(md: rbml::Doc) -> Vec<ast::Attribute> {
match reader::maybe_get_doc(md, tag_attributes) {
Some(attrs_d) => {
reader::tagged_docs(attrs_d, tag_attribute).map(|attr_doc| {
assert_eq!(meta_items.len(), 1);
let meta_item = meta_items.into_iter().nth(0).unwrap();
codemap::Spanned {
- node: hir::Attribute_ {
+ node: ast::Attribute_ {
id: attr::mk_attr_id(),
- style: hir::AttrOuter,
+ style: ast::AttrStyle::Outer,
value: meta_item,
is_sugared_doc: is_sugared_doc,
},
write!(out, "\n\n")
}
-pub fn get_crate_attributes(data: &[u8]) -> Vec<hir::Attribute> {
+pub fn get_crate_attributes(data: &[u8]) -> Vec<ast::Attribute> {
get_attributes(rbml::Doc::new(data))
}
// crate to the correct local crate number.
pub fn translate_def_id(cdata: Cmd, did: DefId) -> DefId {
if did.is_local() {
- return DefId { krate: cdata.cnum, node: did.node };
+ return DefId { krate: cdata.cnum, index: did.index };
}
match cdata.cnum_map.borrow().get(&did.krate) {
Some(&n) => {
DefId {
krate: n,
- node: did.node,
+ index: did.index,
}
}
None => panic!("didn't find a crate in the cnum_map")
// for an external crate.
fn reverse_translate_def_id(cdata: Cmd, did: DefId) -> Option<DefId> {
if did.krate == cdata.cnum {
- return Some(DefId { krate: LOCAL_CRATE, node: did.node });
+ return Some(DefId { krate: LOCAL_CRATE, index: did.index });
}
for (&local, &global) in cdata.cnum_map.borrow().iter() {
if global == did.krate {
- return Some(DefId { krate: local, node: did.node });
+ return Some(DefId { krate: local, index: did.index });
}
}
}
pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
- id: ast::NodeId,
+ id: DefIndex,
mut callback: F)
where F: FnMut(DefId),
{
mut callback: F) where
F: FnMut(DefId),
{
- if cdata.cnum == def_id.krate {
- let item_doc = cdata.lookup_item(def_id.node);
- for impl_doc in reader::tagged_docs(item_doc, tag_items_data_item_extension_impl) {
- callback(item_def_id(impl_doc, cdata));
- }
- return;
- }
-
// Do a reverse lookup beforehand to avoid touching the crate_num
// hash map in the loop below.
if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) {
let def_id_u64 = def_to_u64(crate_local_did);
let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls);
- for impl_doc in reader::tagged_docs(impls_doc, tag_impls_impl) {
- let impl_trait = reader::get_doc(impl_doc, tag_impls_impl_trait_def_id);
- if reader::doc_as_u64(impl_trait) == def_id_u64 {
- callback(item_def_id(impl_doc, cdata));
+ for trait_doc in reader::tagged_docs(impls_doc, tag_impls_trait) {
+ let trait_def_id = reader::get_doc(trait_doc, tag_def_id);
+ if reader::doc_as_u64(trait_def_id) != def_id_u64 {
+ continue;
+ }
+ for impl_doc in reader::tagged_docs(trait_doc, tag_impls_trait_impl) {
+ callback(translated_def_id(cdata, impl_doc));
}
}
}
}
-pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
+pub fn get_trait_of_item(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt)
-> Option<DefId> {
let item_doc = cdata.lookup_item(id);
let parent_item_id = match item_parent_item(cdata, item_doc) {
None => return None,
Some(item_id) => item_id,
};
- let parent_item_doc = cdata.lookup_item(parent_item_id.node);
+ let parent_item_doc = cdata.lookup_item(parent_item_id.index);
match item_family(parent_item_doc) {
Trait => Some(item_def_id(parent_item_doc, cdata)),
Impl | DefaultImpl => {
}).collect()
}
-pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<ast::NodeId> {
+pub fn get_plugin_registrar_fn(data: &[u8]) -> Option<DefIndex> {
reader::maybe_get_doc(rbml::Doc::new(data), tag_plugin_registrar_fn)
- .map(|doc| reader::doc_as_u32(doc))
+ .map(|doc| DefIndex::from_u32(reader::doc_as_u32(doc)))
}
pub fn each_exported_macro<F>(data: &[u8], intr: &IdentInterner, mut f: F) where
- F: FnMut(ast::Name, Vec<hir::Attribute>, String) -> bool,
+ F: FnMut(ast::Name, Vec<ast::Attribute>, String) -> bool,
{
let macros = reader::get_doc(rbml::Doc::new(data), tag_macro_defs);
for macro_doc in reader::tagged_docs(macros, tag_macro_def) {
}).collect()
}
-pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec<String> {
+pub fn get_method_arg_names(cdata: Cmd, id: DefIndex) -> Vec<String> {
let method_doc = cdata.lookup_item(id);
match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
Some(args_doc) => {
reader::tagged_docs(items, tag_reachable_id).map(|doc| {
DefId {
krate: cdata.cnum,
- node: reader::doc_as_u32(doc),
+ index: DefIndex::from_u32(reader::doc_as_u32(doc)),
}
}).collect()
}
-pub fn is_typedef(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_typedef(cdata: Cmd, id: DefIndex) -> bool {
let item_doc = cdata.lookup_item(id);
match item_family(item_doc) {
Type => true,
}
}
-pub fn is_const_fn(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_const_fn(cdata: Cmd, id: DefIndex) -> bool {
let item_doc = cdata.lookup_item(id);
match fn_constness(item_doc) {
hir::Constness::Const => true,
}
}
-pub fn is_impl(cdata: Cmd, id: ast::NodeId) -> bool {
+pub fn is_impl(cdata: Cmd, id: DefIndex) -> bool {
let item_doc = cdata.lookup_item(id);
match item_family(item_doc) {
Impl => true,
for p in reader::tagged_docs(doc, tag_type_param_def) {
let bd =
TyDecoder::with_doc(tcx, cdata.cnum, p,
- &mut |_, did| translate_def_id(cdata, did))
+ &mut |did| translate_def_id(cdata, did))
.parse_type_param_def();
types.push(bd.space, bd);
}
let bounds = reader::tagged_docs(rp_doc, tag_items_data_region).map(|p| {
TyDecoder::with_doc(tcx, cdata.cnum, p,
- &mut |_, did| translate_def_id(cdata, did))
+ &mut |did| translate_def_id(cdata, did))
.parse_region()
}).collect();
ty::Generics { types: types, regions: regions }
}
+fn doc_predicate<'tcx>(cdata: Cmd,
+ doc: rbml::Doc,
+ tcx: &ty::ctxt<'tcx>)
+ -> ty::Predicate<'tcx>
+{
+ let predicate_pos = cdata.xref_index.lookup(
+ cdata.data(), reader::doc_as_u32(doc)).unwrap() as usize;
+ TyDecoder::new(
+ cdata.data(), cdata.cnum, predicate_pos, tcx,
+ &mut |did| translate_def_id(cdata, did)
+ ).parse_predicate()
+}
+
fn doc_predicates<'tcx>(base_doc: rbml::Doc,
tcx: &ty::ctxt<'tcx>,
cdata: Cmd,
let doc = reader::get_doc(base_doc, tag);
let mut predicates = subst::VecPerParamSpace::empty();
- for predicate_doc in reader::tagged_docs(doc, tag_predicate) {
- let space_doc = reader::get_doc(predicate_doc, tag_predicate_space);
- let space = subst::ParamSpace::from_uint(reader::doc_as_u8(space_doc) as usize);
-
- let data_doc = reader::get_doc(predicate_doc, tag_predicate_data);
- let data =
- TyDecoder::with_doc(tcx, cdata.cnum, data_doc,
- &mut |_, did| translate_def_id(cdata, did))
- .parse_predicate();
-
- predicates.push(space, data);
+ for predicate_doc in reader::tagged_docs(doc, tag_type_predicate) {
+ predicates.push(subst::TypeSpace,
+ doc_predicate(cdata, predicate_doc, tcx));
+ }
+ for predicate_doc in reader::tagged_docs(doc, tag_self_predicate) {
+ predicates.push(subst::SelfSpace,
+ doc_predicate(cdata, predicate_doc, tcx));
+ }
+ for predicate_doc in reader::tagged_docs(doc, tag_fn_predicate) {
+ predicates.push(subst::FnSpace,
+ doc_predicate(cdata, predicate_doc, tcx));
}
ty::GenericPredicates { predicates: predicates }
}
-pub fn is_defaulted_trait(cdata: Cmd, trait_id: ast::NodeId) -> bool {
+pub fn is_defaulted_trait(cdata: Cmd, trait_id: DefIndex) -> bool {
let trait_doc = cdata.lookup_item(trait_id);
assert!(item_family(trait_doc) == Family::Trait);
let defaulted_doc = reader::get_doc(trait_doc, tag_defaulted_trait);
reader::doc_as_u8(defaulted_doc) != 0
}
-pub fn is_default_impl(cdata: Cmd, impl_id: ast::NodeId) -> bool {
+pub fn is_default_impl(cdata: Cmd, impl_id: DefIndex) -> bool {
let impl_doc = cdata.lookup_item(impl_id);
item_family(impl_doc) == Family::DefaultImpl
}
}).collect()
}
-pub fn is_extern_fn(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt) -> bool {
+pub fn is_extern_fn(cdata: Cmd, id: DefIndex, tcx: &ty::ctxt) -> bool {
let item_doc = match cdata.get_item(id) {
Some(doc) => doc,
None => return false,
false
}
}
+
+pub fn closure_kind(cdata: Cmd, closure_id: DefIndex) -> ty::ClosureKind {
+ let closure_doc = cdata.lookup_item(closure_id);
+ let closure_kind_doc = reader::get_doc(closure_doc, tag_items_closure_kind);
+ let mut decoder = reader::Decoder::new(closure_kind_doc);
+ ty::ClosureKind::decode(&mut decoder).unwrap()
+}
+
+pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &ty::ctxt<'tcx>)
+ -> ty::ClosureTy<'tcx> {
+ let closure_doc = cdata.lookup_item(closure_id);
+ let closure_ty_doc = reader::get_doc(closure_doc, tag_items_closure_ty);
+ TyDecoder::with_doc(tcx, cdata.cnum, closure_ty_doc, &mut |did| translate_def_id(cdata, did))
+ .parse_closure_ty()
+}
+
+fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
+ match reader::maybe_get_doc(item_doc, tag_def_key) {
+ Some(def_key_doc) => {
+ let mut decoder = reader::Decoder::new(def_key_doc);
+ hir_map::DefKey::decode(&mut decoder).unwrap()
+ }
+ None => {
+ panic!("failed to find block with tag {:?} for item with family {:?}",
+ tag_def_key,
+ item_family(item_doc))
+ }
+ }
+}
+
+pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath {
+ debug!("def_path(id={:?})", id);
+ hir_map::definitions::make_def_path(id, |parent| {
+ debug!("def_path: parent={:?}", parent);
+ let parent_doc = cdata.lookup_item(parent);
+ def_key(parent_doc)
+ })
+}
use session::config;
use metadata::common::*;
use metadata::cstore;
+use metadata::cstore::LOCAL_CRATE;
use metadata::decoder;
use metadata::tyencode;
-use metadata::index::{self, IndexEntry};
+use metadata::index::{self, IndexData};
use metadata::inline::InlinedItemRef;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::dependency_format::Linkage;
use middle::stability;
+use middle::subst;
use middle::ty::{self, Ty};
use util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use std::io::prelude::*;
use std::io::{Cursor, SeekFrom};
use std::rc::Rc;
+use std::u32;
use syntax::abi;
-use syntax::ast::{NodeId, Name, CRATE_NODE_ID, CrateNum};
+use syntax::ast::{self, NodeId, Name, CRATE_NODE_ID, CrateNum};
+use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::diagnostic::SpanHandler;
use syntax::parse::token::special_idents;
use syntax;
use rbml::writer::Encoder;
-use rustc_front::hir as ast;
+use rustc_front::hir;
use rustc_front::visit::Visitor;
use rustc_front::visit;
-use rustc_front::attr;
-use rustc_front::attr::AttrMetaMethods;
use front::map::{LinkedPath, PathElem, PathElems};
use front::map as ast_map;
pub reachable: &'a NodeSet,
}
-fn encode_name(rbml_w: &mut Encoder, name: Name) {
- rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str());
+impl<'a, 'tcx> EncodeContext<'a,'tcx> {
+ fn local_id(&self, def_id: DefId) -> NodeId {
+ self.tcx.map.as_local_node_id(def_id).unwrap()
+ }
+}
+
+/// "interned" entries referenced by id
+#[derive(PartialEq, Eq, Hash)]
+pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
+
+struct CrateIndex<'tcx> {
+ items: IndexData,
+ xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
}
-fn encode_impl_type_basename(rbml_w: &mut Encoder, name: Name) {
- rbml_w.wr_tagged_str(tag_item_impl_type_basename, &name.as_str());
+impl<'tcx> CrateIndex<'tcx> {
+ fn record(&mut self, id: DefId, rbml_w: &mut Encoder) {
+ let position = rbml_w.mark_stable_position();
+ self.items.record(id, position);
+ }
+
+ fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
+ let old_len = self.xrefs.len() as u32;
+ *self.xrefs.entry(xref).or_insert(old_len)
+ }
+}
+
+fn encode_name(rbml_w: &mut Encoder, name: Name) {
+ rbml_w.wr_tagged_str(tag_paths_data_name, &name.as_str());
}
fn encode_def_id(rbml_w: &mut Encoder, id: DefId) {
rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id));
}
+/// For every DefId that we create a metadata item for, we include a
+/// serialized copy of its DefKey, which allows us to recreate a path.
+fn encode_def_id_and_key(ecx: &EncodeContext,
+ rbml_w: &mut Encoder,
+ def_id: DefId)
+{
+ encode_def_id(rbml_w, def_id);
+ encode_def_key(ecx, rbml_w, def_id);
+}
+
+fn encode_def_key(ecx: &EncodeContext,
+ rbml_w: &mut Encoder,
+ def_id: DefId)
+{
+ rbml_w.start_tag(tag_def_key);
+ let def_key = ecx.tcx.map.def_key(def_id);
+ def_key.encode(rbml_w);
+ rbml_w.end_tag();
+}
+
fn encode_trait_ref<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
trait_ref: ty::TraitRef<'tcx>,
}
pub fn def_to_u64(did: DefId) -> u64 {
- (did.krate as u64) << 32 | (did.node as u64)
+ assert!(did.index.as_u32() < u32::MAX);
+ (did.krate as u64) << 32 | (did.index.as_usize() as u64)
}
pub fn def_to_string(did: DefId) -> String {
- format!("{}:{}", did.krate, did.node)
+ format!("{}:{}", did.krate, did.index.as_usize())
}
fn encode_item_variances(rbml_w: &mut Encoder,
ecx: &EncodeContext,
id: NodeId) {
- let v = ecx.tcx.item_variances(DefId::local(id));
+ let v = ecx.tcx.item_variances(ecx.tcx.map.local_def_id(id));
rbml_w.start_tag(tag_item_variances);
v.encode(rbml_w);
rbml_w.end_tag();
fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
+ index: &mut CrateIndex<'tcx>,
id: NodeId) {
encode_bounds_and_type(rbml_w,
ecx,
- &ecx.tcx.lookup_item_type(DefId::local(id)),
- &ecx.tcx.lookup_predicates(DefId::local(id)));
+ index,
+ &ecx.tcx.lookup_item_type(ecx.tcx.map.local_def_id(id)),
+ &ecx.tcx.lookup_predicates(ecx.tcx.map.local_def_id(id)));
}
fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
+ index: &mut CrateIndex<'tcx>,
scheme: &ty::TypeScheme<'tcx>,
predicates: &ty::GenericPredicates<'tcx>) {
- encode_generics(rbml_w, ecx, &scheme.generics, &predicates, tag_item_generics);
+ encode_generics(rbml_w, ecx, index,
+ &scheme.generics, &predicates, tag_item_generics);
encode_type(ecx, rbml_w, scheme.ty);
}
rbml_w.end_tag();
}
-fn encode_method_fty<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
- rbml_w: &mut Encoder,
- typ: &ty::BareFnTy<'tcx>) {
- rbml_w.start_tag(tag_item_method_fty);
-
- let ty_str_ctxt = &tyencode::ctxt {
- diag: ecx.diag,
- ds: def_to_string,
- tcx: ecx.tcx,
- abbrevs: &ecx.type_abbrevs
- };
- tyencode::enc_bare_fn_ty(rbml_w, ty_str_ctxt, typ);
-
- rbml_w.end_tag();
-}
-
fn encode_symbol(ecx: &EncodeContext,
rbml_w: &mut Encoder,
id: NodeId) {
}
fn encode_struct_fields(rbml_w: &mut Encoder,
- variant: ty::VariantDef,
- origin: DefId) {
+ variant: ty::VariantDef) {
for f in &variant.fields {
if f.name == special_idents::unnamed_field.name {
rbml_w.start_tag(tag_item_unnamed_field);
}
encode_struct_field_family(rbml_w, f.vis);
encode_def_id(rbml_w, f.did);
- rbml_w.wr_tagged_u64(tag_item_field_origin, def_to_u64(origin));
rbml_w.end_tag();
}
}
-fn encode_enum_variant_info(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- id: NodeId,
- vis: ast::Visibility,
- index: &mut Vec<IndexEntry>) {
+fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ id: NodeId,
+ vis: hir::Visibility,
+ index: &mut CrateIndex<'tcx>) {
debug!("encode_enum_variant_info(id={})", id);
let mut disr_val = 0;
- let def = ecx.tcx.lookup_adt_def(DefId::local(id));
+ let def = ecx.tcx.lookup_adt_def(ecx.tcx.map.local_def_id(id));
for variant in &def.variants {
let vid = variant.did;
- assert!(vid.is_local());
+ let variant_node_id = ecx.local_id(vid);
- if let ty::VariantKind::Dict = variant.kind() {
+ if let ty::VariantKind::Struct = variant.kind() {
// tuple-like enum variant fields aren't really items so
// don't try to encode them.
for field in &variant.fields {
}
}
- index.push(IndexEntry {
- node: vid.node,
- pos: rbml_w.mark_stable_position(),
- });
+ index.record(vid, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, vid);
+ encode_def_id_and_key(ecx, rbml_w, vid);
encode_family(rbml_w, match variant.kind() {
ty::VariantKind::Unit | ty::VariantKind::Tuple => 'v',
- ty::VariantKind::Dict => 'V'
+ ty::VariantKind::Struct => 'V'
});
encode_name(rbml_w, variant.name);
- encode_parent_item(rbml_w, DefId::local(id));
+ encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(id));
encode_visibility(rbml_w, vis);
let attrs = ecx.tcx.get_attrs(vid);
let stab = stability::lookup(ecx.tcx, vid);
encode_stability(rbml_w, stab);
- encode_struct_fields(rbml_w, variant, vid);
+ encode_struct_fields(rbml_w, variant);
let specified_disr_val = variant.disr_val;
if specified_disr_val != disr_val {
encode_disr_val(ecx, rbml_w, specified_disr_val);
disr_val = specified_disr_val;
}
- encode_bounds_and_type_for_item(rbml_w, ecx, vid.node);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id);
- ecx.tcx.map.with_path(vid.node, |path| encode_path(rbml_w, path));
+ ecx.tcx.map.with_path(variant_node_id, |path| encode_path(rbml_w, path));
rbml_w.end_tag();
disr_val = disr_val.wrapping_add(1);
}
rbml_w.end_tag();
}
-fn encode_reexported_static_method(rbml_w: &mut Encoder,
- exp: &def::Export,
- method_def_id: DefId,
- method_name: Name) {
- debug!("(encode reexported static method) {}::{}",
- exp.name, method_name);
- rbml_w.start_tag(tag_items_data_item_reexport);
- rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
- def_to_u64(method_def_id));
- rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
- &format!("{}::{}", exp.name,
- method_name));
- rbml_w.end_tag();
-}
-
-fn encode_reexported_static_base_methods(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- exp: &def::Export)
- -> bool {
- let impl_items = ecx.tcx.impl_items.borrow();
- match ecx.tcx.inherent_impls.borrow().get(&exp.def_id) {
- Some(implementations) => {
- for base_impl_did in implementations.iter() {
- for &method_did in impl_items.get(base_impl_did).unwrap() {
- let impl_item = ecx.tcx.impl_or_trait_item(method_did.def_id());
- if let ty::MethodTraitItem(ref m) = impl_item {
- encode_reexported_static_method(rbml_w,
- exp,
- m.def_id,
- m.name);
- }
- }
- }
-
- true
- }
- None => { false }
- }
-}
-
-fn encode_reexported_static_trait_methods(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- exp: &def::Export)
- -> bool {
- match ecx.tcx.trait_items_cache.borrow().get(&exp.def_id) {
- Some(trait_items) => {
- for trait_item in trait_items.iter() {
- if let ty::MethodTraitItem(ref m) = *trait_item {
- encode_reexported_static_method(rbml_w,
- exp,
- m.def_id,
- m.name);
- }
- }
- true
- }
- None => { false }
- }
-}
-
-fn encode_reexported_static_methods(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- mod_path: PathElems,
- exp: &def::Export) {
- if let Some(ast_map::NodeItem(item)) = ecx.tcx.map.find(exp.def_id.node) {
- let path_differs = ecx.tcx.map.with_path(exp.def_id.node, |path| {
- let (mut a, mut b) = (path, mod_path.clone());
- loop {
- match (a.next(), b.next()) {
- (None, None) => return true,
- (None, _) | (_, None) => return false,
- (Some(x), Some(y)) => if x != y { return false },
- }
- }
- });
-
- //
- // We don't need to reexport static methods on items
- // declared in the same module as our `pub use ...` since
- // that's done when we encode the item itself.
- //
- // The only exception is when the reexport *changes* the
- // name e.g. `pub use Foo = self::Bar` -- we have
- // encoded metadata for static methods relative to Bar,
- // but not yet for Foo.
- //
- if path_differs || item.ident.name != exp.name {
- if !encode_reexported_static_base_methods(ecx, rbml_w, exp) {
- if encode_reexported_static_trait_methods(ecx, rbml_w, exp) {
- debug!("(encode reexported static methods) {} [trait]",
- item.ident.name);
- }
- }
- else {
- debug!("(encode reexported static methods) {} [base]",
- item.ident.name);
- }
- }
- }
-}
-
/// Iterates through "auxiliary node IDs", which are node IDs that describe
/// top-level items that are sub-items of the given item. Specifically:
///
/// * For newtype structs, iterates through the node ID of the constructor.
-fn each_auxiliary_node_id<F>(item: &ast::Item, callback: F) -> bool where
+fn each_auxiliary_node_id<F>(item: &hir::Item, callback: F) -> bool where
F: FnOnce(NodeId) -> bool,
{
let mut continue_ = true;
match item.node {
- ast::ItemStruct(ref struct_def, _) => {
+ hir::ItemStruct(ref struct_def, _) => {
// If this is a newtype struct, return the constructor.
- match struct_def.ctor_id {
- Some(ctor_id) if !struct_def.fields.is_empty() &&
- struct_def.fields[0].node.kind.is_unnamed() => {
- continue_ = callback(ctor_id);
- }
- _ => {}
+ if struct_def.is_tuple() {
+ continue_ = callback(struct_def.id());
}
}
_ => {}
fn encode_reexports(ecx: &EncodeContext,
rbml_w: &mut Encoder,
- id: NodeId,
- path: PathElems) {
+ id: NodeId) {
debug!("(encoding info for module) encoding reexports for {}", id);
match ecx.reexports.get(&id) {
Some(exports) => {
debug!("(encoding info for module) found reexports for {}", id);
for exp in exports {
- debug!("(encoding info for module) reexport '{}' ({}/{}) for \
+ debug!("(encoding info for module) reexport '{}' ({:?}) for \
{}",
exp.name,
- exp.def_id.krate,
- exp.def_id.node,
+ exp.def_id,
id);
rbml_w.start_tag(tag_items_data_item_reexport);
rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
&exp.name.as_str());
rbml_w.end_tag();
- encode_reexported_static_methods(ecx, rbml_w, path.clone(), exp);
}
},
None => debug!("(encoding info for module) found no reexports for {}", id),
fn encode_info_for_mod(ecx: &EncodeContext,
rbml_w: &mut Encoder,
- md: &ast::Mod,
+ md: &hir::Mod,
attrs: &[ast::Attribute],
id: NodeId,
path: PathElems,
name: Name,
- vis: ast::Visibility) {
+ vis: hir::Visibility) {
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, DefId::local(id));
+ encode_def_id_and_key(ecx, rbml_w, ecx.tcx.map.local_def_id(id));
encode_family(rbml_w, 'm');
encode_name(rbml_w, name);
debug!("(encoding info for module) encoding info for module ID {}", id);
// Encode info about all the module children.
for item in &md.items {
rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(DefId::local(item.id)));
+ def_to_u64(ecx.tcx.map.local_def_id(item.id)));
each_auxiliary_node_id(&**item, |auxiliary_node_id| {
rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(DefId::local(auxiliary_node_id)));
+ def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
true
});
-
- if let ast::ItemImpl(..) = item.node {
- let (ident, did) = (item.ident, item.id);
- debug!("(encoding info for module) ... encoding impl {} ({}/{})",
- ident,
- did, ecx.tcx.map.node_to_string(did));
-
- rbml_w.wr_tagged_u64(tag_mod_impl, def_to_u64(DefId::local(did)));
- }
}
encode_path(rbml_w, path.clone());
encode_visibility(rbml_w, vis);
- let stab = stability::lookup(ecx.tcx, DefId::local(id));
+ let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(id));
encode_stability(rbml_w, stab);
// Encode the reexports of this module, if this module is public.
- if vis == ast::Public {
+ if vis == hir::Public {
debug!("(encoding info for module) encoding reexports for {}", id);
- encode_reexports(ecx, rbml_w, id, path);
+ encode_reexports(ecx, rbml_w, id);
}
encode_attributes(rbml_w, attrs);
}
fn encode_struct_field_family(rbml_w: &mut Encoder,
- visibility: ast::Visibility) {
+ visibility: hir::Visibility) {
encode_family(rbml_w, match visibility {
- ast::Public => 'g',
- ast::Inherited => 'N'
+ hir::Public => 'g',
+ hir::Inherited => 'N'
});
}
-fn encode_visibility(rbml_w: &mut Encoder, visibility: ast::Visibility) {
+fn encode_visibility(rbml_w: &mut Encoder, visibility: hir::Visibility) {
let ch = match visibility {
- ast::Public => 'y',
- ast::Inherited => 'i',
+ hir::Public => 'y',
+ hir::Inherited => 'i',
};
rbml_w.wr_tagged_u8(tag_items_data_item_visibility, ch as u8);
}
-fn encode_constness(rbml_w: &mut Encoder, constness: ast::Constness) {
+fn encode_constness(rbml_w: &mut Encoder, constness: hir::Constness) {
rbml_w.start_tag(tag_items_data_item_constness);
let ch = match constness {
- ast::Constness::Const => 'c',
- ast::Constness::NotConst => 'n',
+ hir::Constness::Const => 'c',
+ hir::Constness::NotConst => 'n',
};
rbml_w.wr_str(&ch.to_string());
rbml_w.end_tag();
}
}
- fn encode_mutability(m: ast::Mutability) -> u8 {
+ fn encode_mutability(m: hir::Mutability) -> u8 {
match m {
- ast::MutImmutable => 'i' as u8,
- ast::MutMutable => 'm' as u8,
+ hir::MutImmutable => 'i' as u8,
+ hir::MutMutable => 'm' as u8,
}
}
}
rbml_w.wr_tagged_u8(tag_item_trait_item_sort, sort as u8);
}
-fn encode_parent_sort(rbml_w: &mut Encoder, sort: char) {
- rbml_w.wr_tagged_u8(tag_item_trait_parent_sort, sort as u8);
-}
-
-fn encode_provided_source(rbml_w: &mut Encoder,
- source_opt: Option<DefId>) {
- if let Some(source) = source_opt {
- rbml_w.wr_tagged_u64(tag_item_method_provided_source, def_to_u64(source));
- }
-}
-
fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
field: ty::FieldDef<'tcx>,
- global_index: &mut Vec<IndexEntry>) {
+ index: &mut CrateIndex<'tcx>) {
let nm = field.name;
- let id = field.did.node;
+ let id = ecx.local_id(field.did);
- let pos = rbml_w.mark_stable_position();
- global_index.push(IndexEntry {
- node: id,
- pos: pos,
- });
+ index.record(field.did, rbml_w);
rbml_w.start_tag(tag_items_data_item);
debug!("encode_field: encoding {} {}", nm, id);
encode_struct_field_family(rbml_w, field.vis);
encode_name(rbml_w, nm);
- encode_bounds_and_type_for_item(rbml_w, ecx, id);
- encode_def_id(rbml_w, DefId::local(id));
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, id);
+ encode_def_id_and_key(ecx, rbml_w, field.did);
let stab = stability::lookup(ecx.tcx, field.did);
encode_stability(rbml_w, stab);
rbml_w.end_tag();
}
-fn encode_info_for_struct_ctor(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- name: Name,
- ctor_id: NodeId,
- index: &mut Vec<IndexEntry>,
- struct_id: NodeId) {
- index.push(IndexEntry {
- node: ctor_id,
- pos: rbml_w.mark_stable_position(),
- });
+fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ name: Name,
+ ctor_id: NodeId,
+ index: &mut CrateIndex<'tcx>,
+ struct_id: NodeId) {
+ let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
+ index.record(ctor_def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, DefId::local(ctor_id));
+ encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
encode_family(rbml_w, 'o');
- encode_bounds_and_type_for_item(rbml_w, ecx, ctor_id);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, ctor_id);
encode_name(rbml_w, name);
ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
- encode_parent_item(rbml_w, DefId::local(struct_id));
+ encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(struct_id));
if ecx.item_symbols.borrow().contains_key(&ctor_id) {
encode_symbol(ecx, rbml_w, ctor_id);
}
- let stab = stability::lookup(ecx.tcx, DefId::local(ctor_id));
+ let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(ctor_id));
encode_stability(rbml_w, stab);
// indicate that this is a tuple struct ctor, because downstream users will normally want
fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a, 'tcx>,
+ index: &mut CrateIndex<'tcx>,
generics: &ty::Generics<'tcx>,
predicates: &ty::GenericPredicates<'tcx>,
tag: usize)
rbml_w.end_tag();
}
- encode_predicates_in_current_doc(rbml_w, ecx, predicates);
+ encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
rbml_w.end_tag();
}
fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
- ecx: &EncodeContext<'a,'tcx>,
+ _ecx: &EncodeContext<'a,'tcx>,
+ index: &mut CrateIndex<'tcx>,
predicates: &ty::GenericPredicates<'tcx>)
{
- let ty_str_ctxt = &tyencode::ctxt {
- diag: ecx.diag,
- ds: def_to_string,
- tcx: ecx.tcx,
- abbrevs: &ecx.type_abbrevs
- };
-
for (space, _, predicate) in predicates.predicates.iter_enumerated() {
- rbml_w.start_tag(tag_predicate);
-
- rbml_w.wr_tagged_u8(tag_predicate_space, space as u8);
-
- rbml_w.start_tag(tag_predicate_data);
- tyencode::enc_predicate(rbml_w, ty_str_ctxt, predicate);
- rbml_w.end_tag();
+ let tag = match space {
+ subst::TypeSpace => tag_type_predicate,
+ subst::SelfSpace => tag_self_predicate,
+ subst::FnSpace => tag_fn_predicate
+ };
- rbml_w.end_tag();
+ rbml_w.wr_tagged_u32(tag,
+ index.add_xref(XRef::Predicate(predicate.clone())));
}
}
fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
ecx: &EncodeContext<'a,'tcx>,
+ index: &mut CrateIndex<'tcx>,
predicates: &ty::GenericPredicates<'tcx>,
tag: usize)
{
rbml_w.start_tag(tag);
- encode_predicates_in_current_doc(rbml_w, ecx, predicates);
+ encode_predicates_in_current_doc(rbml_w, ecx, index, predicates);
rbml_w.end_tag();
}
fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
+ index: &mut CrateIndex<'tcx>,
method_ty: &ty::Method<'tcx>) {
- encode_def_id(rbml_w, method_ty.def_id);
+ encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
encode_name(rbml_w, method_ty.name);
- encode_generics(rbml_w, ecx, &method_ty.generics, &method_ty.predicates,
+ encode_generics(rbml_w, ecx, index,
+ &method_ty.generics, &method_ty.predicates,
tag_method_ty_generics);
- encode_method_fty(ecx, rbml_w, &method_ty.fty);
encode_visibility(rbml_w, method_ty.vis);
encode_explicit_self(rbml_w, &method_ty.explicit_self);
match method_ty.explicit_self {
}
_ => encode_family(rbml_w, METHOD_FAMILY)
}
- encode_provided_source(rbml_w, method_ty.provided_source);
}
-fn encode_info_for_associated_const(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- associated_const: &ty::AssociatedConst,
- impl_path: PathElems,
- parent_id: NodeId,
- impl_item_opt: Option<&ast::ImplItem>) {
+fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ index: &mut CrateIndex<'tcx>,
+ associated_const: &ty::AssociatedConst,
+ impl_path: PathElems,
+ parent_id: NodeId,
+ impl_item_opt: Option<&hir::ImplItem>) {
debug!("encode_info_for_associated_const({:?},{:?})",
associated_const.def_id,
associated_const.name);
+ index.record(associated_const.def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, associated_const.def_id);
+ encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
encode_name(rbml_w, associated_const.name);
encode_visibility(rbml_w, associated_const.vis);
encode_family(rbml_w, 'C');
- encode_provided_source(rbml_w, associated_const.default);
- encode_parent_item(rbml_w, DefId::local(parent_id));
+ encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
encode_item_sort(rbml_w, 'C');
- encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());
+ encode_bounds_and_type_for_item(rbml_w, ecx, index,
+ ecx.local_id(associated_const.def_id));
let stab = stability::lookup(ecx.tcx, associated_const.def_id);
encode_stability(rbml_w, stab);
if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
- encode_inlined_item(ecx, rbml_w, InlinedItemRef::ImplItem(DefId::local(parent_id), ii));
+ encode_inlined_item(ecx,
+ rbml_w,
+ InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
+ ii));
}
rbml_w.end_tag();
fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
+ index: &mut CrateIndex<'tcx>,
m: &ty::Method<'tcx>,
impl_path: PathElems,
is_default_impl: bool,
parent_id: NodeId,
- impl_item_opt: Option<&ast::ImplItem>) {
+ impl_item_opt: Option<&hir::ImplItem>) {
debug!("encode_info_for_method: {:?} {:?}", m.def_id,
m.name);
+ index.record(m.def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_method_ty_fields(ecx, rbml_w, m);
- encode_parent_item(rbml_w, DefId::local(parent_id));
+ encode_method_ty_fields(ecx, rbml_w, index, m);
+ encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
encode_item_sort(rbml_w, 'r');
let stab = stability::lookup(ecx.tcx, m.def_id);
encode_stability(rbml_w, stab);
- // The type for methods gets encoded twice, which is unfortunate.
- encode_bounds_and_type_for_item(rbml_w, ecx, m.def_id.local_id());
+ let m_node_id = ecx.local_id(m.def_id);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, m_node_id);
let elem = ast_map::PathName(m.name);
encode_path(rbml_w, impl_path.chain(Some(elem)));
if let Some(impl_item) = impl_item_opt {
- if let ast::MethodImplItem(ref sig, _) = impl_item.node {
+ if let hir::MethodImplItem(ref sig, _) = impl_item.node {
encode_attributes(rbml_w, &impl_item.attrs);
let scheme = ecx.tcx.lookup_item_type(m.def_id);
let any_types = !scheme.generics.types.is_empty();
let needs_inline = any_types || is_default_impl ||
attr::requests_inline(&impl_item.attrs);
- if needs_inline || sig.constness == ast::Constness::Const {
- encode_inlined_item(ecx, rbml_w, InlinedItemRef::ImplItem(DefId::local(parent_id),
- impl_item));
+ if needs_inline || sig.constness == hir::Constness::Const {
+ encode_inlined_item(ecx,
+ rbml_w,
+ InlinedItemRef::ImplItem(ecx.tcx.map.local_def_id(parent_id),
+ impl_item));
}
encode_constness(rbml_w, sig.constness);
if !any_types {
- encode_symbol(ecx, rbml_w, m.def_id.node);
+ let m_id = ecx.local_id(m.def_id);
+ encode_symbol(ecx, rbml_w, m_id);
}
encode_method_argument_names(rbml_w, &sig.decl);
}
fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
+ index: &mut CrateIndex<'tcx>,
associated_type: &ty::AssociatedType<'tcx>,
impl_path: PathElems,
parent_id: NodeId,
- impl_item_opt: Option<&ast::ImplItem>) {
+ impl_item_opt: Option<&hir::ImplItem>) {
debug!("encode_info_for_associated_type({:?},{:?})",
associated_type.def_id,
associated_type.name);
+ index.record(associated_type.def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, associated_type.def_id);
+ encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
encode_name(rbml_w, associated_type.name);
encode_visibility(rbml_w, associated_type.vis);
encode_family(rbml_w, 'y');
- encode_parent_item(rbml_w, DefId::local(parent_id));
+ encode_parent_item(rbml_w, ecx.tcx.map.local_def_id(parent_id));
encode_item_sort(rbml_w, 't');
let stab = stability::lookup(ecx.tcx, associated_type.def_id);
if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
} else {
- encode_predicates(rbml_w, ecx,
+ encode_predicates(rbml_w, ecx, index,
&ecx.tcx.lookup_predicates(associated_type.def_id),
tag_item_generics);
}
}
fn encode_method_argument_names(rbml_w: &mut Encoder,
- decl: &ast::FnDecl) {
+ decl: &hir::FnDecl) {
rbml_w.start_tag(tag_method_argument_names);
for arg in &decl.inputs {
let tag = tag_method_argument_name;
- if let ast::PatIdent(_, ref path1, _) = arg.pat.node {
+ if let hir::PatIdent(_, ref path1, _) = arg.pat.node {
let name = path1.node.name.as_str();
rbml_w.wr_tagged_bytes(tag, name.as_bytes());
} else {
}
}
-// Encodes the implementations of a trait defined in this crate.
-fn encode_extension_implementations(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- trait_def_id: DefId) {
- assert!(trait_def_id.is_local());
- let def = ecx.tcx.lookup_trait_def(trait_def_id);
-
- def.for_each_impl(ecx.tcx, |impl_def_id| {
- rbml_w.start_tag(tag_items_data_item_extension_impl);
- encode_def_id(rbml_w, impl_def_id);
- rbml_w.end_tag();
- });
-}
-
fn encode_stability(rbml_w: &mut Encoder, stab_opt: Option<&attr::Stability>) {
stab_opt.map(|stab| {
rbml_w.start_tag(tag_items_data_item_stability);
});
}
-fn encode_info_for_item(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- item: &ast::Item,
- index: &mut Vec<IndexEntry>,
- path: PathElems,
- vis: ast::Visibility) {
- let tcx = ecx.tcx;
+fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ xrefs: FnvHashMap<XRef<'tcx>, u32>)
+{
+ let ty_str_ctxt = &tyencode::ctxt {
+ diag: ecx.diag,
+ ds: def_to_string,
+ tcx: ecx.tcx,
+ abbrevs: &ecx.type_abbrevs
+ };
- fn add_to_index(item: &ast::Item, rbml_w: &mut Encoder,
- index: &mut Vec<IndexEntry>) {
- index.push(IndexEntry {
- node: item.id,
- pos: rbml_w.mark_stable_position(),
- });
+ let mut xref_positions = vec![0; xrefs.len()];
+ rbml_w.start_tag(tag_xref_data);
+ for (xref, id) in xrefs.into_iter() {
+ xref_positions[id as usize] = rbml_w.mark_stable_position() as u32;
+ match xref {
+ XRef::Predicate(p) => {
+ tyencode::enc_predicate(rbml_w, ty_str_ctxt, &p)
+ }
+ }
}
+ rbml_w.end_tag();
+
+ rbml_w.start_tag(tag_xref_index);
+ index::write_dense_index(xref_positions, rbml_w.writer);
+ rbml_w.end_tag();
+}
+
+fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ item: &hir::Item,
+ index: &mut CrateIndex<'tcx>,
+ path: PathElems,
+ vis: hir::Visibility) {
+ let tcx = ecx.tcx;
debug!("encoding info for item at {}",
tcx.sess.codemap().span_to_string(item.span));
- let def_id = DefId::local(item.id);
- let stab = stability::lookup(tcx, DefId::local(item.id));
+ let def_id = ecx.tcx.map.local_def_id(item.id);
+ let stab = stability::lookup(tcx, ecx.tcx.map.local_def_id(item.id));
match item.node {
- ast::ItemStatic(_, m, _) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemStatic(_, m, _) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
- if m == ast::MutMutable {
+ encode_def_id_and_key(ecx, rbml_w, def_id);
+ if m == hir::MutMutable {
encode_family(rbml_w, 'b');
} else {
encode_family(rbml_w, 'c');
}
- encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
encode_symbol(ecx, rbml_w, item.id);
- encode_name(rbml_w, item.ident.name);
+ encode_name(rbml_w, item.name);
encode_path(rbml_w, path);
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
encode_attributes(rbml_w, &item.attrs);
rbml_w.end_tag();
}
- ast::ItemConst(_, _) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemConst(_, _) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'C');
- encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
- encode_name(rbml_w, item.ident.name);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
+ encode_name(rbml_w, item.name);
encode_path(rbml_w, path);
encode_attributes(rbml_w, &item.attrs);
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
encode_stability(rbml_w, stab);
rbml_w.end_tag();
}
- ast::ItemFn(ref decl, _, constness, _, ref generics, _) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, FN_FAMILY);
let tps_len = generics.ty_params.len();
- encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
- encode_name(rbml_w, item.ident.name);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
+ encode_name(rbml_w, item.name);
encode_path(rbml_w, path);
encode_attributes(rbml_w, &item.attrs);
let needs_inline = tps_len > 0 || attr::requests_inline(&item.attrs);
- if needs_inline || constness == ast::Constness::Const {
+ if needs_inline || constness == hir::Constness::Const {
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
}
if tps_len == 0 {
encode_method_argument_names(rbml_w, &**decl);
rbml_w.end_tag();
}
- ast::ItemMod(ref m) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemMod(ref m) => {
+ index.record(def_id, rbml_w);
encode_info_for_mod(ecx,
rbml_w,
m,
&item.attrs,
item.id,
path,
- item.ident.name,
+ item.name,
item.vis);
}
- ast::ItemForeignMod(ref fm) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemForeignMod(ref fm) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'n');
- encode_name(rbml_w, item.ident.name);
+ encode_name(rbml_w, item.name);
encode_path(rbml_w, path);
// Encode all the items in this module.
for foreign_item in &fm.items {
rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(DefId::local(foreign_item.id)));
+ def_to_u64(ecx.tcx.map.local_def_id(foreign_item.id)));
}
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
rbml_w.end_tag();
}
- ast::ItemTy(..) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemTy(..) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'y');
- encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
- encode_name(rbml_w, item.ident.name);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
+ encode_name(rbml_w, item.name);
encode_path(rbml_w, path);
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
rbml_w.end_tag();
}
- ast::ItemEnum(ref enum_definition, _) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemEnum(ref enum_definition, _) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 't');
encode_item_variances(rbml_w, ecx, item.id);
- encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
- encode_name(rbml_w, item.ident.name);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
+ encode_name(rbml_w, item.name);
encode_attributes(rbml_w, &item.attrs);
encode_repr_attrs(rbml_w, ecx, &item.attrs);
for v in &enum_definition.variants {
- encode_variant_id(rbml_w, DefId::local(v.node.id));
+ encode_variant_id(rbml_w, ecx.tcx.map.local_def_id(v.node.data.id()));
}
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
encode_path(rbml_w, path);
vis,
index);
}
- ast::ItemStruct(ref struct_def, _) => {
+ hir::ItemStruct(ref struct_def, _) => {
let def = ecx.tcx.lookup_adt_def(def_id);
let variant = def.struct_variant();
- for field in &variant.fields {
- encode_field(ecx, rbml_w, field, index);
- }
-
/* Index the class*/
- add_to_index(item, rbml_w, index);
+ index.record(def_id, rbml_w);
/* Now, make an item for the class itself */
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'S');
- encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
encode_item_variances(rbml_w, ecx, item.id);
- encode_name(rbml_w, item.ident.name);
+ encode_name(rbml_w, item.name);
encode_attributes(rbml_w, &item.attrs);
encode_path(rbml_w, path.clone());
encode_stability(rbml_w, stab);
/* Encode def_ids for each field and method
for methods, write all the stuff get_trait_method
needs to know*/
- encode_struct_fields(rbml_w, variant, def_id);
+ encode_struct_fields(rbml_w, variant);
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Item(item));
// Encode inherent implementations for this structure.
encode_inherent_implementations(ecx, rbml_w, def_id);
+ if !struct_def.is_struct() {
+ let ctor_did = ecx.tcx.map.local_def_id(struct_def.id());
+ rbml_w.wr_tagged_u64(tag_items_data_item_struct_ctor,
+ def_to_u64(ctor_did));
+ }
+
rbml_w.end_tag();
+ for field in &variant.fields {
+ encode_field(ecx, rbml_w, field, index);
+ }
+
// If this is a tuple-like struct, encode the type of the constructor.
- match struct_def.ctor_id {
- Some(ctor_id) => {
- encode_info_for_struct_ctor(ecx, rbml_w, item.ident.name,
- ctor_id, index, def_id.node);
- }
- None => {}
+ if !struct_def.is_struct() {
+ encode_info_for_struct_ctor(ecx, rbml_w, item.name, struct_def.id(), index, item.id);
}
}
- ast::ItemDefaultImpl(unsafety, _) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemDefaultImpl(unsafety, _) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'd');
- encode_name(rbml_w, item.ident.name);
+ encode_name(rbml_w, item.name);
encode_unsafety(rbml_w, unsafety);
- let trait_ref = tcx.impl_trait_ref(DefId::local(item.id)).unwrap();
+ let trait_ref = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)).unwrap();
encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
rbml_w.end_tag();
}
- ast::ItemImpl(unsafety, polarity, _, _, ref ty, ref ast_items) => {
+ hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => {
// We need to encode information about the default methods we
// have inherited, so we drive this based on the impl structure.
let impl_items = tcx.impl_items.borrow();
let items = impl_items.get(&def_id).unwrap();
- add_to_index(item, rbml_w, index);
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'i');
- encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
- encode_name(rbml_w, item.ident.name);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, item.id);
+ encode_name(rbml_w, item.name);
encode_attributes(rbml_w, &item.attrs);
encode_unsafety(rbml_w, unsafety);
encode_polarity(rbml_w, polarity);
- match tcx.custom_coerce_unsized_kinds.borrow().get(&DefId::local(item.id)) {
+ match tcx.custom_coerce_unsized_kinds.borrow().get(&ecx.tcx.map.local_def_id(item.id)) {
Some(&kind) => {
rbml_w.start_tag(tag_impl_coerce_unsized_kind);
kind.encode(rbml_w);
None => {}
}
- match ty.node {
- ast::TyPath(None, ref path) if path.segments.len() == 1 => {
- let name = path.segments.last().unwrap().identifier.name;
- encode_impl_type_basename(rbml_w, name);
- }
- _ => {}
- }
for &item_def_id in items {
rbml_w.start_tag(tag_item_impl_item);
match item_def_id {
}
rbml_w.end_tag();
}
- if let Some(trait_ref) = tcx.impl_trait_ref(DefId::local(item.id)) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(ecx.tcx.map.local_def_id(item.id)) {
encode_trait_ref(rbml_w, ecx, trait_ref, tag_item_trait_ref);
}
encode_path(rbml_w, path.clone());
None
};
- index.push(IndexEntry {
- node: trait_item_def_id.def_id().node,
- pos: rbml_w.mark_stable_position(),
- });
-
match tcx.impl_or_trait_item(trait_item_def_id.def_id()) {
ty::ConstTraitItem(ref associated_const) => {
encode_info_for_associated_const(ecx,
rbml_w,
+ index,
&*associated_const,
path.clone(),
item.id,
ty::MethodTraitItem(ref method_type) => {
encode_info_for_method(ecx,
rbml_w,
+ index,
&**method_type,
path.clone(),
false,
ty::TypeTraitItem(ref associated_type) => {
encode_info_for_associated_type(ecx,
rbml_w,
+ index,
&**associated_type,
path.clone(),
item.id,
}
}
}
- ast::ItemTrait(_, _, _, ref ms) => {
- add_to_index(item, rbml_w, index);
+ hir::ItemTrait(_, _, _, ref ms) => {
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, def_id);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_family(rbml_w, 'I');
encode_item_variances(rbml_w, ecx, item.id);
let trait_def = tcx.lookup_trait_def(def_id);
encode_paren_sugar(rbml_w, trait_def.paren_sugar);
encode_defaulted(rbml_w, tcx.trait_has_default_impl(def_id));
encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
- encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates,
+ encode_generics(rbml_w, ecx, index,
+ &trait_def.generics, &trait_predicates,
tag_item_generics);
- encode_predicates(rbml_w, ecx, &tcx.lookup_super_predicates(def_id),
+ encode_predicates(rbml_w, ecx, index,
+ &tcx.lookup_super_predicates(def_id),
tag_item_super_predicates);
encode_trait_ref(rbml_w, ecx, trait_def.trait_ref, tag_item_trait_ref);
- encode_name(rbml_w, item.ident.name);
+ encode_name(rbml_w, item.name);
encode_attributes(rbml_w, &item.attrs);
encode_visibility(rbml_w, vis);
encode_stability(rbml_w, stab);
}
encode_path(rbml_w, path.clone());
- // Encode the implementations of this trait.
- encode_extension_implementations(ecx, rbml_w, def_id);
-
// Encode inherent implementations for this trait.
encode_inherent_implementations(ecx, rbml_w, def_id);
for (i, &item_def_id) in r.iter().enumerate() {
assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
- index.push(IndexEntry {
- node: item_def_id.def_id().node,
- pos: rbml_w.mark_stable_position(),
- });
-
+ index.record(item_def_id.def_id(), rbml_w);
rbml_w.start_tag(tag_items_data_item);
encode_parent_item(rbml_w, def_id);
match trait_item_type {
ty::ConstTraitItem(associated_const) => {
encode_name(rbml_w, associated_const.name);
- encode_def_id(rbml_w, associated_const.def_id);
+ encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
encode_visibility(rbml_w, associated_const.vis);
- encode_provided_source(rbml_w, associated_const.default);
-
let elem = ast_map::PathName(associated_const.name);
encode_path(rbml_w,
path.clone().chain(Some(elem)));
- encode_item_sort(rbml_w, 'C');
encode_family(rbml_w, 'C');
- encode_bounds_and_type_for_item(rbml_w, ecx,
- associated_const.def_id.local_id());
+ encode_bounds_and_type_for_item(rbml_w, ecx, index,
+ ecx.local_id(associated_const.def_id));
is_nonstatic_method = false;
}
ty::MethodTraitItem(method_ty) => {
let method_def_id = item_def_id.def_id();
- encode_method_ty_fields(ecx, rbml_w, &*method_ty);
+ encode_method_ty_fields(ecx, rbml_w, index, &*method_ty);
let elem = ast_map::PathName(method_ty.name);
encode_path(rbml_w,
METHOD_FAMILY);
}
}
- encode_bounds_and_type_for_item(rbml_w, ecx, method_def_id.local_id());
+ encode_bounds_and_type_for_item(rbml_w, ecx, index,
+ ecx.local_id(method_def_id));
is_nonstatic_method = method_ty.explicit_self !=
ty::StaticExplicitSelfCategory;
}
ty::TypeTraitItem(associated_type) => {
encode_name(rbml_w, associated_type.name);
- encode_def_id(rbml_w, associated_type.def_id);
+ encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
let elem = ast_map::PathName(associated_type.name);
encode_path(rbml_w,
}
}
- encode_parent_sort(rbml_w, 't');
-
let trait_item = &*ms[i];
encode_attributes(rbml_w, &trait_item.attrs);
match trait_item.node {
- ast::ConstTraitItem(_, _) => {
+ hir::ConstTraitItem(_, ref default) => {
+ if default.is_some() {
+ encode_item_sort(rbml_w, 'C');
+ } else {
+ encode_item_sort(rbml_w, 'c');
+ }
+
encode_inlined_item(ecx, rbml_w,
InlinedItemRef::TraitItem(def_id, trait_item));
}
- ast::MethodTraitItem(ref sig, ref body) => {
+ hir::MethodTraitItem(ref sig, ref body) => {
// If this is a static method, we've already
// encoded this.
if is_nonstatic_method {
// FIXME: I feel like there is something funny
// going on.
- encode_bounds_and_type_for_item(rbml_w, ecx,
- item_def_id.def_id().local_id());
+ encode_bounds_and_type_for_item(rbml_w, ecx, index,
+ ecx.local_id(item_def_id.def_id()));
}
if body.is_some() {
encode_method_argument_names(rbml_w, &sig.decl);
}
- ast::TypeTraitItem(..) => {}
+ hir::TypeTraitItem(..) => {}
}
rbml_w.end_tag();
}
}
- ast::ItemExternCrate(_) | ast::ItemUse(_) => {
+ hir::ItemExternCrate(_) | hir::ItemUse(_) => {
// these are encoded separately
}
}
}
-fn encode_info_for_foreign_item(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- nitem: &ast::ForeignItem,
- index: &mut Vec<IndexEntry>,
- path: PathElems,
- abi: abi::Abi) {
- index.push(IndexEntry {
- node: nitem.id,
- pos: rbml_w.mark_stable_position(),
- });
+fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ nitem: &hir::ForeignItem,
+ index: &mut CrateIndex<'tcx>,
+ path: PathElems,
+ abi: abi::Abi) {
+ let def_id = ecx.tcx.map.local_def_id(nitem.id);
+ index.record(def_id, rbml_w);
rbml_w.start_tag(tag_items_data_item);
- encode_def_id(rbml_w, DefId::local(nitem.id));
+ encode_def_id_and_key(ecx, rbml_w, def_id);
encode_visibility(rbml_w, nitem.vis);
match nitem.node {
- ast::ForeignItemFn(ref fndecl, _) => {
+ hir::ForeignItemFn(ref fndecl, _) => {
encode_family(rbml_w, FN_FAMILY);
- encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id);
- encode_name(rbml_w, nitem.ident.name);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
+ encode_name(rbml_w, nitem.name);
if abi == abi::RustIntrinsic || abi == abi::PlatformIntrinsic {
encode_inlined_item(ecx, rbml_w, InlinedItemRef::Foreign(nitem));
}
encode_attributes(rbml_w, &*nitem.attrs);
- let stab = stability::lookup(ecx.tcx, DefId::local(nitem.id));
+ let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id));
encode_stability(rbml_w, stab);
encode_symbol(ecx, rbml_w, nitem.id);
encode_method_argument_names(rbml_w, &*fndecl);
}
- ast::ForeignItemStatic(_, mutbl) => {
+ hir::ForeignItemStatic(_, mutbl) => {
if mutbl {
encode_family(rbml_w, 'b');
} else {
encode_family(rbml_w, 'c');
}
- encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id);
+ encode_bounds_and_type_for_item(rbml_w, ecx, index, nitem.id);
encode_attributes(rbml_w, &*nitem.attrs);
- let stab = stability::lookup(ecx.tcx, DefId::local(nitem.id));
+ let stab = stability::lookup(ecx.tcx, ecx.tcx.map.local_def_id(nitem.id));
encode_stability(rbml_w, stab);
encode_symbol(ecx, rbml_w, nitem.id);
- encode_name(rbml_w, nitem.ident.name);
+ encode_name(rbml_w, nitem.name);
}
}
encode_path(rbml_w, path);
rbml_w.end_tag();
}
-fn my_visit_expr(_e: &ast::Expr) { }
-
-fn my_visit_item(i: &ast::Item,
+fn my_visit_expr(expr: &hir::Expr,
rbml_w: &mut Encoder,
ecx: &EncodeContext,
- index: &mut Vec<IndexEntry>) {
+ index: &mut CrateIndex) {
+ match expr.node {
+ hir::ExprClosure(..) => {
+ let def_id = ecx.tcx.map.local_def_id(expr.id);
+
+ index.record(def_id, rbml_w);
+
+ rbml_w.start_tag(tag_items_data_item);
+ encode_def_id_and_key(ecx, rbml_w, def_id);
+
+ rbml_w.start_tag(tag_items_closure_ty);
+ write_closure_type(ecx, rbml_w, &ecx.tcx.tables.borrow().closure_tys[&def_id]);
+ rbml_w.end_tag();
+
+ rbml_w.start_tag(tag_items_closure_kind);
+ ecx.tcx.closure_kind(def_id).encode(rbml_w).unwrap();
+ rbml_w.end_tag();
+
+ ecx.tcx.map.with_path(expr.id, |path| encode_path(rbml_w, path));
+
+ rbml_w.end_tag();
+ }
+ _ => { }
+ }
+}
+
+fn my_visit_item<'a, 'tcx>(i: &hir::Item,
+ rbml_w: &mut Encoder,
+ ecx: &EncodeContext<'a, 'tcx>,
+ index: &mut CrateIndex<'tcx>) {
ecx.tcx.map.with_path(i.id, |path| {
encode_info_for_item(ecx, rbml_w, i, index, path, i.vis);
});
}
-fn my_visit_foreign_item(ni: &ast::ForeignItem,
- rbml_w: &mut Encoder,
- ecx: &EncodeContext,
- index: &mut Vec<IndexEntry>) {
+fn my_visit_foreign_item<'a, 'tcx>(ni: &hir::ForeignItem,
+ rbml_w: &mut Encoder,
+ ecx: &EncodeContext<'a, 'tcx>,
+ index: &mut CrateIndex<'tcx>) {
debug!("writing foreign item {}::{}",
ecx.tcx.map.path_to_string(ni.id),
- ni.ident);
+ ni.name);
let abi = ecx.tcx.map.get_foreign_abi(ni.id);
ecx.tcx.map.with_path(ni.id, |path| {
struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
rbml_w_for_visit_item: &'a mut Encoder<'b>,
ecx: &'a EncodeContext<'c,'tcx>,
- index: &'a mut Vec<IndexEntry>,
+ index: &'a mut CrateIndex<'tcx>,
}
impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
- fn visit_expr(&mut self, ex: &ast::Expr) {
+ fn visit_expr(&mut self, ex: &hir::Expr) {
visit::walk_expr(self, ex);
- my_visit_expr(ex);
+ my_visit_expr(ex, self.rbml_w_for_visit_item, self.ecx, self.index);
}
- fn visit_item(&mut self, i: &ast::Item) {
+ fn visit_item(&mut self, i: &hir::Item) {
visit::walk_item(self, i);
- my_visit_item(i,
- self.rbml_w_for_visit_item,
- self.ecx,
- self.index);
+ my_visit_item(i, self.rbml_w_for_visit_item, self.ecx, self.index);
}
- fn visit_foreign_item(&mut self, ni: &ast::ForeignItem) {
+ fn visit_foreign_item(&mut self, ni: &hir::ForeignItem) {
visit::walk_foreign_item(self, ni);
- my_visit_foreign_item(ni,
- self.rbml_w_for_visit_item,
- self.ecx,
- self.index);
+ my_visit_foreign_item(ni, self.rbml_w_for_visit_item, self.ecx, self.index);
}
}
-fn encode_info_for_items(ecx: &EncodeContext,
- rbml_w: &mut Encoder,
- krate: &ast::Crate)
- -> Vec<IndexEntry> {
- let mut index = Vec::new();
+fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
+ rbml_w: &mut Encoder,
+ krate: &hir::Crate)
+ -> CrateIndex<'tcx> {
+ let mut index = CrateIndex {
+ items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
+ xrefs: FnvHashMap()
+ };
rbml_w.start_tag(tag_items_data);
- index.push(IndexEntry {
- node: CRATE_NODE_ID,
- pos: rbml_w.mark_stable_position(),
- });
+
+ index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
encode_info_for_mod(ecx,
rbml_w,
&krate.module,
CRATE_NODE_ID,
[].iter().cloned().chain(LinkedPath::empty()),
syntax::parse::token::special_idents::invalid.name,
- ast::Public);
+ hir::Public);
visit::walk_crate(&mut EncodeVisitor {
index: &mut index,
index
}
-
-
-
-fn encode_index(rbml_w: &mut Encoder, index: Vec<IndexEntry>)
-{
+fn encode_item_index(rbml_w: &mut Encoder, index: IndexData) {
rbml_w.start_tag(tag_index);
- index::write_index(index, rbml_w.writer);
+ index.write_index(rbml_w.writer);
rbml_w.end_tag();
}
rbml_w.end_tag();
}
-fn encode_unsafety(rbml_w: &mut Encoder, unsafety: ast::Unsafety) {
+fn encode_unsafety(rbml_w: &mut Encoder, unsafety: hir::Unsafety) {
let byte: u8 = match unsafety {
- ast::Unsafety::Normal => 0,
- ast::Unsafety::Unsafe => 1,
+ hir::Unsafety::Normal => 0,
+ hir::Unsafety::Unsafe => 1,
};
rbml_w.wr_tagged_u8(tag_unsafety, byte);
}
rbml_w.end_tag();
}
-fn encode_polarity(rbml_w: &mut Encoder, polarity: ast::ImplPolarity) {
+fn encode_polarity(rbml_w: &mut Encoder, polarity: hir::ImplPolarity) {
let byte: u8 = match polarity {
- ast::ImplPolarity::Positive => 0,
- ast::ImplPolarity::Negative => 1,
+ hir::ImplPolarity::Positive => 0,
+ hir::ImplPolarity::Negative => 1,
};
rbml_w.wr_tagged_u8(tag_polarity, byte);
}
fn encode_lang_items(ecx: &EncodeContext, rbml_w: &mut Encoder) {
rbml_w.start_tag(tag_lang_items);
- for (i, &def_id) in ecx.tcx.lang_items.items() {
- if let Some(id) = def_id {
- if id.is_local() {
+ for (i, &opt_def_id) in ecx.tcx.lang_items.items() {
+ if let Some(def_id) = opt_def_id {
+ if def_id.is_local() {
rbml_w.start_tag(tag_lang_items_item);
rbml_w.wr_tagged_u32(tag_lang_items_item_id, i as u32);
- rbml_w.wr_tagged_u32(tag_lang_items_item_node_id, id.node as u32);
+ rbml_w.wr_tagged_u32(tag_lang_items_item_index, def_id.index.as_u32());
rbml_w.end_tag();
}
}
fn encode_plugin_registrar_fn(ecx: &EncodeContext, rbml_w: &mut Encoder) {
match ecx.tcx.sess.plugin_registrar_fn.get() {
- Some(id) => { rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, id); }
+ Some(id) => {
+ let def_id = ecx.tcx.map.local_def_id(id);
+ rbml_w.wr_tagged_u32(tag_plugin_registrar_fn, def_id.index.as_u32());
+ }
None => {}
}
}
/// Serialize the text of the exported macros
fn encode_macro_defs(rbml_w: &mut Encoder,
- krate: &ast::Crate) {
+ krate: &hir::Crate) {
rbml_w.start_tag(tag_macro_defs);
for def in &krate.exported_macros {
rbml_w.start_tag(tag_macro_def);
- encode_name(rbml_w, def.ident.name);
+ encode_name(rbml_w, def.name);
encode_attributes(rbml_w, &def.attrs);
rbml_w.wr_tagged_str(tag_macro_def_body,
rbml_w.end_tag();
}
-fn encode_struct_field_attrs(rbml_w: &mut Encoder, krate: &ast::Crate) {
- struct StructFieldVisitor<'a, 'b:'a> {
- rbml_w: &'a mut Encoder<'b>,
+fn encode_struct_field_attrs(ecx: &EncodeContext,
+ rbml_w: &mut Encoder,
+ krate: &hir::Crate) {
+ struct StructFieldVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
+ ecx: &'a EncodeContext<'b, 'tcx>,
+ rbml_w: &'a mut Encoder<'c>,
}
- impl<'a, 'b, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b> {
- fn visit_struct_field(&mut self, field: &ast::StructField) {
+ impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for StructFieldVisitor<'a, 'b, 'c, 'tcx> {
+ fn visit_struct_field(&mut self, field: &hir::StructField) {
self.rbml_w.start_tag(tag_struct_field);
- self.rbml_w.wr_tagged_u32(tag_struct_field_id, field.node.id);
+ let def_id = self.ecx.tcx.map.local_def_id(field.node.id);
+ encode_def_id(self.rbml_w, def_id);
encode_attributes(self.rbml_w, &field.node.attrs);
self.rbml_w.end_tag();
}
}
rbml_w.start_tag(tag_struct_fields);
- visit::walk_crate(&mut StructFieldVisitor {
- rbml_w: rbml_w
- }, krate);
+ visit::walk_crate(&mut StructFieldVisitor { ecx: ecx, rbml_w: rbml_w }, krate);
rbml_w.end_tag();
}
-struct ImplVisitor<'a, 'b:'a, 'c:'a, 'tcx:'b> {
- ecx: &'a EncodeContext<'b, 'tcx>,
- rbml_w: &'a mut Encoder<'c>,
+struct ImplVisitor<'a, 'tcx:'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ impls: FnvHashMap<DefId, Vec<DefId>>
}
-impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
- fn visit_item(&mut self, item: &ast::Item) {
- if let ast::ItemImpl(_, _, _, Some(ref trait_ref), _, _) = item.node {
- let def_id = self.ecx.tcx.def_map.borrow().get(&trait_ref.ref_id).unwrap().def_id();
-
- // Load eagerly if this is an implementation of the Drop trait
- // or if the trait is not defined in this crate.
- if Some(def_id) == self.ecx.tcx.lang_items.drop_trait() ||
- def_id.krate != LOCAL_CRATE {
- self.rbml_w.start_tag(tag_impls_impl);
- encode_def_id(self.rbml_w, DefId::local(item.id));
- self.rbml_w.wr_tagged_u64(tag_impls_impl_trait_def_id, def_to_u64(def_id));
- self.rbml_w.end_tag();
+impl<'a, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'tcx> {
+ fn visit_item(&mut self, item: &hir::Item) {
+ if let hir::ItemImpl(..) = item.node {
+ let impl_id = self.tcx.map.local_def_id(item.id);
+ if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id) {
+ self.impls.entry(trait_ref.def_id)
+ .or_insert(vec![])
+ .push(impl_id);
}
}
visit::walk_item(self, item);
}
}
-/// Encodes implementations that are eagerly loaded.
-///
-/// None of this is necessary in theory; we can load all implementations
-/// lazily. However, in two cases the optimizations to lazily load
-/// implementations are not yet implemented. These two cases, which require us
-/// to load implementations eagerly, are:
-///
-/// * Destructors (implementations of the Drop trait).
-///
-/// * Implementations of traits not defined in this crate.
+/// Encodes an index, mapping each trait to its (local) implementations.
fn encode_impls<'a>(ecx: &'a EncodeContext,
- krate: &ast::Crate,
+ krate: &hir::Crate,
rbml_w: &'a mut Encoder) {
- rbml_w.start_tag(tag_impls);
+ let mut visitor = ImplVisitor {
+ tcx: ecx.tcx,
+ impls: FnvHashMap()
+ };
+ visit::walk_crate(&mut visitor, krate);
- {
- let mut visitor = ImplVisitor {
- ecx: ecx,
- rbml_w: rbml_w,
- };
- visit::walk_crate(&mut visitor, krate);
+ rbml_w.start_tag(tag_impls);
+ for (trait_, trait_impls) in visitor.impls {
+ rbml_w.start_tag(tag_impls_trait);
+ encode_def_id(rbml_w, trait_);
+ for impl_ in trait_impls {
+ rbml_w.wr_tagged_u64(tag_impls_trait_impl, def_to_u64(impl_));
+ }
+ rbml_w.end_tag();
}
-
rbml_w.end_tag();
}
fn encode_misc_info(ecx: &EncodeContext,
- krate: &ast::Crate,
+ krate: &hir::Crate,
rbml_w: &mut Encoder) {
rbml_w.start_tag(tag_misc_info);
rbml_w.start_tag(tag_misc_info_crate_items);
for item in &krate.module.items {
rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(DefId::local(item.id)));
+ def_to_u64(ecx.tcx.map.local_def_id(item.id)));
each_auxiliary_node_id(&**item, |auxiliary_node_id| {
rbml_w.wr_tagged_u64(tag_mod_child,
- def_to_u64(DefId::local(auxiliary_node_id)));
+ def_to_u64(ecx.tcx.map.local_def_id(auxiliary_node_id)));
true
});
}
// Encode reexports for the root module.
- encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty()));
+ encode_reexports(ecx, rbml_w, 0);
rbml_w.end_tag();
rbml_w.end_tag();
// definition (as that's not defined in this crate).
fn encode_reachable(ecx: &EncodeContext, rbml_w: &mut Encoder) {
rbml_w.start_tag(tag_reachable_ids);
- for id in ecx.reachable {
- rbml_w.wr_tagged_u32(tag_reachable_id, *id);
+ for &id in ecx.reachable {
+ let def_id = ecx.tcx.map.local_def_id(id);
+ rbml_w.wr_tagged_u32(tag_reachable_id, def_id.index.as_u32());
}
rbml_w.end_tag();
}
rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str());
}
+fn encode_rustc_version(rbml_w: &mut Encoder) {
+ rbml_w.wr_tagged_str(tag_rustc_version, &rustc_version());
+}
+
fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) {
rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name);
}
#[allow(non_upper_case_globals)]
pub const metadata_encoding_version : &'static [u8] = &[b'r', b'u', b's', b't', 0, 0, 0, 2 ];
-pub fn encode_metadata(parms: EncodeParams, krate: &ast::Crate) -> Vec<u8> {
+pub fn encode_metadata(parms: EncodeParams, krate: &hir::Crate) -> Vec<u8> {
let mut wr = Cursor::new(Vec::new());
encode_metadata_inner(&mut wr, parms, krate);
fn encode_metadata_inner(wr: &mut Cursor<Vec<u8>>,
parms: EncodeParams,
- krate: &ast::Crate) {
+ krate: &hir::Crate) {
struct Stats {
attr_bytes: u64,
dep_bytes: u64,
misc_bytes: u64,
item_bytes: u64,
index_bytes: u64,
+ xref_bytes: u64,
zero_bytes: u64,
total_bytes: u64,
}
misc_bytes: 0,
item_bytes: 0,
index_bytes: 0,
+ xref_bytes: 0,
zero_bytes: 0,
total_bytes: 0,
};
let mut rbml_w = Encoder::new(wr);
+ encode_rustc_version(&mut rbml_w);
encode_crate_name(&mut rbml_w, &ecx.link_meta.crate_name);
encode_crate_triple(&mut rbml_w, &tcx.sess.opts.target_triple);
encode_hash(&mut rbml_w, &ecx.link_meta.crate_hash);
// Encode and index the items.
rbml_w.start_tag(tag_items);
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- let items_index = encode_info_for_items(&ecx, &mut rbml_w, krate);
+ let index = encode_info_for_items(&ecx, &mut rbml_w, krate);
stats.item_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
rbml_w.end_tag();
i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
- encode_index(&mut rbml_w, items_index);
+ encode_item_index(&mut rbml_w, index.items);
stats.index_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
- encode_struct_field_attrs(&mut rbml_w, krate);
+ i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
+ encode_xrefs(&ecx, &mut rbml_w, index.xrefs);
+ stats.xref_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap() - i;
+
+ encode_struct_field_attrs(&ecx, &mut rbml_w, krate);
stats.total_bytes = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
println!(" misc bytes: {}", stats.misc_bytes);
println!(" item bytes: {}", stats.item_bytes);
println!(" index bytes: {}", stats.index_bytes);
+ println!(" xref bytes: {}", stats.xref_bytes);
println!(" zero bytes: {}", stats.zero_bytes);
println!(" total bytes: {}", stats.total_bytes);
}
}
// Get the encoded string for a type
-pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> String {
+pub fn encoded_ty<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> Vec<u8> {
let mut wr = Cursor::new(Vec::new());
tyencode::enc_ty(&mut Encoder::new(&mut wr), &tyencode::ctxt {
diag: tcx.sess.diagnostic(),
tcx: tcx,
abbrevs: &RefCell::new(FnvHashMap())
}, t);
- String::from_utf8(wr.into_inner()).unwrap()
+ wr.into_inner()
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use middle::def_id::{DefId, DefIndex};
+use rbml;
use std::io::{Cursor, Write};
use std::slice;
use std::u32;
-use syntax::ast::NodeId;
-#[derive(Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
-pub struct IndexEntry {
- pub node: NodeId,
- pub pos: u64
-}
-
-#[derive(Debug)]
-pub struct IndexArrayEntry {
- bits: u32,
- first_pos: u32
+/// As part of the metadata, we generate an index that stores, for
+/// each DefIndex, the position of the corresponding RBML document (if
+/// any). This is just a big `[u32]` slice, where an entry of
+/// `u32::MAX` indicates that there is no RBML document. This little
+/// struct just stores the offsets within the metadata of the start
+/// and end of this slice. These are actually part of an RBML
+/// document, but for looking things up in the metadata, we just
+/// discard the RBML positioning and jump directly to the data.
+pub struct Index {
+ data_start: usize,
+ data_end: usize,
}
-impl IndexArrayEntry {
- fn encode_to<W: Write>(&self, b: &mut W) {
- write_be_u32(b, self.bits);
- write_be_u32(b, self.first_pos);
+impl Index {
+ /// Given the RBML doc representing the index, save the offests
+ /// for later.
+ pub fn from_rbml(index: rbml::Doc) -> Index {
+ Index { data_start: index.start, data_end: index.end }
}
- fn decode_from(b: &[u32]) -> Self {
- IndexArrayEntry {
- bits: b[0].to_be(),
- first_pos: b[1].to_be()
+ /// Given the metadata, extract out the offset of a particular
+ /// DefIndex (if any).
+ #[inline(never)]
+ pub fn lookup_item(&self, bytes: &[u8], def_index: DefIndex) -> Option<u32> {
+ let words = bytes_to_words(&bytes[self.data_start..self.data_end]);
+ let index = def_index.as_usize();
+
+ debug!("lookup_item: index={:?} words.len={:?}",
+ index, words.len());
+
+ let position = u32::from_be(words[index]);
+ if position == u32::MAX {
+ debug!("lookup_item: position=u32::MAX");
+ None
+ } else {
+ debug!("lookup_item: position={:?}", position);
+ Some(position)
}
}
}
-/// The Item Index
-///
-/// This index maps the NodeId of each item to its location in the
-/// metadata.
-///
-/// The index is a sparse bit-vector consisting of a index-array
-/// and a position-array. Each entry in the index-array handles 32 nodes.
-/// The first word is a bit-array consisting of the nodes that hold items,
-/// the second is the index of the first of the items in the position-array.
-/// If there is a large set of non-item trailing nodes, they can be omitted
-/// from the index-array.
-///
-/// The index is serialized as an array of big-endian 32-bit words.
-/// The first word is the number of items in the position-array.
-/// Then, for each item, its position in the metadata follows.
-/// After that the index-array is stored.
-///
-/// struct index {
-/// u32 item_count;
-/// u32 items[self.item_count];
-/// struct { u32 bits; u32 offset; } positions[..];
-/// }
-pub struct Index {
- position_start: usize,
- index_start: usize,
- index_end: usize,
+/// While we are generating the metadata, we also track the position
+/// of each DefIndex. It is not required that all definitions appear
+/// in the metadata, nor that they are serialized in order, and
+/// therefore we first allocate the vector here and fill it with
+/// `u32::MAX`. Whenever an index is visited, we fill in the
+/// appropriate spot by calling `record_position`. We should never
+/// visit the same index twice.
+pub struct IndexData {
+ positions: Vec<u32>,
}
-pub fn write_index(mut entries: Vec<IndexEntry>, buf: &mut Cursor<Vec<u8>>) {
- assert!(entries.len() < u32::MAX as usize);
- entries.sort();
+impl IndexData {
+ pub fn new(max_index: usize) -> IndexData {
+ IndexData {
+ positions: vec![u32::MAX; max_index]
+ }
+ }
+
+ pub fn record(&mut self, def_id: DefId, position: u64) {
+ assert!(def_id.is_local());
+ self.record_index(def_id.index, position)
+ }
+
+ pub fn record_index(&mut self, item: DefIndex, position: u64) {
+ let item = item.as_usize();
+
+ assert!(position < (u32::MAX as u64));
+ let position = position as u32;
- let mut last_entry = IndexArrayEntry { bits: 0, first_pos: 0 };
+ assert!(self.positions[item] == u32::MAX,
+ "recorded position for item {:?} twice, first at {:?} and now at {:?}",
+ item, self.positions[item], position);
- write_be_u32(buf, entries.len() as u32);
- for &IndexEntry { pos, .. } in &entries {
- assert!(pos < u32::MAX as u64);
- write_be_u32(buf, pos as u32);
+ self.positions[item] = position;
}
- let mut pos_in_index_array = 0;
- for (i, &IndexEntry { node, .. }) in entries.iter().enumerate() {
- let (x, s) = (node / 32 as u32, node % 32 as u32);
- while x > pos_in_index_array {
- pos_in_index_array += 1;
- last_entry.encode_to(buf);
- last_entry = IndexArrayEntry { bits: 0, first_pos: i as u32 };
+ pub fn write_index(&self, buf: &mut Cursor<Vec<u8>>) {
+ for &position in &self.positions {
+ write_be_u32(buf, position);
}
- last_entry.bits |= 1<<s;
}
- last_entry.encode_to(buf);
+}
- info!("write_index: {} items, {} array entries",
- entries.len(), pos_in_index_array);
+/// A dense index with integer keys. Different API from IndexData (should
+/// these be merged?)
+pub struct DenseIndex {
+ start: usize,
+ end: usize
}
-impl Index {
- fn lookup_index(&self, index: &[u32], i: u32) -> Option<IndexArrayEntry> {
- let ix = (i as usize)*2;
- if ix >= index.len() {
- None
- } else {
- Some(IndexArrayEntry::decode_from(&index[ix..ix+2]))
+impl DenseIndex {
+ pub fn lookup(&self, buf: &[u8], ix: u32) -> Option<u32> {
+ let data = bytes_to_words(&buf[self.start..self.end]);
+ data.get(ix as usize).map(|d| u32::from_be(*d))
+ }
+ pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self {
+ assert!((end-start)%4 == 0 && start <= end && end <= buf.len());
+ DenseIndex {
+ start: start,
+ end: end
}
}
+}
- fn item_from_pos(&self, positions: &[u32], pos: u32) -> u32 {
- positions[pos as usize].to_be()
- }
+pub fn write_dense_index(entries: Vec<u32>, buf: &mut Cursor<Vec<u8>>) {
+ let elen = entries.len();
+ assert!(elen < u32::MAX as usize);
- #[inline(never)]
- pub fn lookup_item(&self, buf: &[u8], node: NodeId) -> Option<u32> {
- let index = bytes_to_words(&buf[self.index_start..self.index_end]);
- let positions = bytes_to_words(&buf[self.position_start..self.index_start]);
- let (x, s) = (node / 32 as u32, node % 32 as u32);
- let result = match self.lookup_index(index, x) {
- Some(IndexArrayEntry { bits, first_pos }) => {
- let bit = 1<<s;
- if bits & bit == 0 {
- None
- } else {
- let prev_nodes_for_entry = (bits&(bit-1)).count_ones();
- Some(self.item_from_pos(
- positions,
- first_pos+prev_nodes_for_entry))
- }
- }
- None => None // trailing zero
- };
- debug!("lookup_item({:?}) = {:?}", node, result);
- result
+ for entry in entries {
+ write_be_u32(buf, entry);
}
- pub fn from_buf(buf: &[u8], start: usize, end: usize) -> Self {
- let buf = bytes_to_words(&buf[start..end]);
- let position_count = buf[0].to_be() as usize;
- let position_len = position_count*4;
- info!("loaded index - position: {}-{}-{}", start, start+position_len, end);
- debug!("index contents are {:?}",
- buf.iter().map(|b| format!("{:08x}", b)).collect::<Vec<_>>().concat());
- assert!(end-4-start >= position_len);
- assert_eq!((end-4-start-position_len)%8, 0);
- Index {
- position_start: start+4,
- index_start: start+position_len+4,
- index_end: end
- }
- }
+ info!("write_dense_index: {} entries", elen);
}
fn write_be_u32<W: Write>(w: &mut W, u: u32) {
assert!(b.len() % 4 == 0);
unsafe { slice::from_raw_parts(b.as_ptr() as *const u32, b.len()/4) }
}
-
-#[test]
-fn test_index() {
- let entries = vec![
- IndexEntry { node: 0, pos: 17 },
- IndexEntry { node: 31, pos: 29 },
- IndexEntry { node: 32, pos: 1175 },
- IndexEntry { node: 191, pos: 21 },
- IndexEntry { node: 128, pos: 34 },
- IndexEntry { node: 145, pos: 70 },
- IndexEntry { node: 305, pos: 93214 },
- IndexEntry { node: 138, pos: 64 },
- IndexEntry { node: 129, pos: 53 },
- IndexEntry { node: 192, pos: 33334 },
- IndexEntry { node: 200, pos: 80123 },
- ];
- let mut c = Cursor::new(vec![]);
- write_index(entries.clone(), &mut c);
- let mut buf = c.into_inner();
- let expected: &[u8] = &[
- 0, 0, 0, 11, // # entries
- // values:
- 0,0,0,17, 0,0,0,29, 0,0,4,151, 0,0,0,34,
- 0,0,0,53, 0,0,0,64, 0,0,0,70, 0,0,0,21,
- 0,0,130,54, 0,1,56,251, 0,1,108,30,
- // index:
- 128,0,0,1,0,0,0,0, 0,0,0,1,0,0,0,2,
- 0,0,0,0,0,0,0,3, 0,0,0,0,0,0,0,3,
- 0,2,4,3,0,0,0,3, 128,0,0,0,0,0,0,7,
- 0,0,1,1,0,0,0,8, 0,0,0,0,0,0,0,10,
- 0,0,0,0,0,0,0,10, 0,2,0,0,0,0,0,10
- ];
- assert_eq!(buf, expected);
-
- // insert some junk padding
- for i in 0..17 { buf.insert(0, i); buf.push(i) }
- let index = Index::from_buf(&buf, 17, buf.len()-17);
-
- // test round-trip
- for i in 0..4096 {
- assert_eq!(index.lookup_item(&buf, i),
- entries.iter().find(|e| e.node == i).map(|n| n.pos as u32));
- }
-}
}
pub fn report_load_errs(&mut self) {
- let message = if !self.rejected_via_hash.is_empty() {
- format!("found possibly newer version of crate `{}`",
- self.ident)
+ let add = match self.root {
+ &None => String::new(),
+ &Some(ref r) => format!(" which `{}` depends on",
+ r.ident)
+ };
+ if !self.rejected_via_hash.is_empty() {
+ span_err!(self.sess, self.span, E0460,
+ "found possibly newer version of crate `{}`{}",
+ self.ident, add);
} else if !self.rejected_via_triple.is_empty() {
- format!("couldn't find crate `{}` with expected target triple {}",
- self.ident, self.triple)
+ span_err!(self.sess, self.span, E0461,
+ "couldn't find crate `{}` with expected target triple {}{}",
+ self.ident, self.triple, add);
} else if !self.rejected_via_kind.is_empty() {
- format!("found staticlib `{}` instead of rlib or dylib", self.ident)
+ span_err!(self.sess, self.span, E0462,
+ "found staticlib `{}` instead of rlib or dylib{}",
+ self.ident, add);
} else {
- format!("can't find crate for `{}`", self.ident)
- };
- let message = match self.root {
- &None => message,
- &Some(ref r) => format!("{} which `{}` depends on",
- message, r.ident)
- };
- self.sess.span_err(self.span, &message[..]);
+ span_err!(self.sess, self.span, E0463,
+ "can't find crate for `{}`{}",
+ self.ident, add);
+ }
if !self.rejected_via_triple.is_empty() {
let mismatches = self.rejected_via_triple.iter();
0 => None,
1 => Some(libraries.into_iter().next().unwrap()),
_ => {
- self.sess.span_err(self.span,
- &format!("multiple matching crates for `{}`",
- self.crate_name));
+ span_err!(self.sess, self.span, E0464,
+ "multiple matching crates for `{}`",
+ self.crate_name);
self.sess.note("candidates:");
for lib in &libraries {
match lib.dylib {
}
};
if ret.is_some() {
- self.sess.span_err(self.span,
- &format!("multiple {} candidates for `{}` \
- found",
- flavor,
- self.crate_name));
+ span_err!(self.sess, self.span, E0465,
+ "multiple {} candidates for `{}` found",
+ flavor, self.crate_name);
self.sess.span_note(self.span,
&format!(r"candidate #1: {}",
ret.as_ref().unwrap().0
ret = Some(get_metadata_section_imp(target, filename));
});
info!("reading {:?} => {:?}", filename.file_name().unwrap(), dur);
- return ret.unwrap();;
+ ret.unwrap()
}
fn get_metadata_section_imp(target: &Target, filename: &Path)
use syntax::visit;
use syntax::visit::Visitor;
use syntax::attr::AttrMetaMethods;
-use rustc_front::attr::AttrMetaMethods as FrontAttrMetaMethods;
struct MacroLoader<'a> {
sess: &'a Session,
}
}
+pub fn call_bad_macro_reexport(a: &Session, b: Span) {
+ span_err!(a, b, E0467, "bad macro reexport");
+}
+
/// Read exported macros.
pub fn read_macro_defs(sess: &Session, krate: &ast::Crate) -> Vec<ast::MacroDef> {
let mut loader = MacroLoader::new(sess);
if let ast::MetaWord(ref name) = attr.node {
sel.insert(name.clone(), attr.span);
} else {
- self.sess.span_err(attr.span, "bad macro import");
+ span_err!(self.sess, attr.span, E0466, "bad macro import");
}
}
}
let names = match attr.meta_item_list() {
Some(names) => names,
None => {
- self.sess.span_err(attr.span, "bad macro reexport");
+ call_bad_macro_reexport(self.sess, attr.span);
continue;
}
};
if let ast::MetaWord(ref name) = attr.node {
reexport.insert(name.clone(), attr.span);
} else {
- self.sess.span_err(attr.span, "bad macro reexport");
+ call_bad_macro_reexport(self.sess, attr.span);
}
}
}
}
if !self.span_whitelist.contains(&vi.span) {
- self.sess.span_err(vi.span, "an `extern crate` loading macros must be at \
- the crate root");
+ span_err!(self.sess, vi.span, E0468,
+ "an `extern crate` loading macros must be at the crate root");
return;
}
if let Some(sel) = import.as_ref() {
for (name, span) in sel {
if !seen.contains(&name) {
- self.sess.span_err(*span, "imported macro not found");
+ span_err!(self.sess, *span, E0469,
+ "imported macro not found");
}
}
}
for (name, span) in &reexport {
if !seen.contains(&name) {
- self.sess.span_err(*span, "reexported macro not found");
+ span_err!(self.sess, *span, E0470,
+ "reexported macro not found");
}
}
}
#![allow(non_camel_case_types)]
-pub use self::DefIdSource::*;
-
use rustc_front::hir;
-use middle::def_id::DefId;
+use middle::def_id::{DefId, DefIndex};
use middle::region;
use middle::subst;
use middle::subst::VecPerParamSpace;
// parse_from_str. Extra parameters are for converting to/from def_ids in the
// data buffer. Whatever format you choose should not contain pipe characters.
-// Def id conversion: when we encounter def-ids, they have to be translated.
-// For example, the crate number must be converted from the crate number used
-// in the library we are reading from into the local crate numbers in use
-// here. To perform this translation, the type decoder is supplied with a
-// conversion function of type `conv_did`.
-//
-// Sometimes, particularly when inlining, the correct translation of the
-// def-id will depend on where it originated from. Therefore, the conversion
-// function is given an indicator of the source of the def-id. See
-// astencode.rs for more information.
-#[derive(Copy, Clone, Debug)]
-pub enum DefIdSource {
- // Identifies a struct, trait, enum, etc.
- NominalType,
-
- // Identifies a type alias (`type X = ...`).
- TypeWithId,
-
- // Identifies a region parameter (`fn foo<'X>() { ... }`).
- RegionParameter,
-
- // Identifies a closure
- ClosureSource
-}
-
-pub type DefIdConvert<'a> = &'a mut FnMut(DefIdSource, DefId) -> DefId;
+pub type DefIdConvert<'a> = &'a mut FnMut(DefId) -> DefId;
pub struct TyDecoder<'a, 'tcx: 'a> {
data: &'a [u8],
return &self.data[start_pos..end_pos];
}
+ fn parse_vuint(&mut self) -> usize {
+ let res = rbml::reader::vuint_at(self.data, self.pos).unwrap();
+ self.pos = res.next;
+ res.val
+ }
+
fn parse_name(&mut self, last: char) -> ast::Name {
fn is_last(b: char, c: char) -> bool { return c == b; }
let bytes = self.scan(|a| is_last(last, a));
ty::BrAnon(id)
}
'[' => {
- let def = self.parse_def(RegionParameter);
- let ident = token::str_to_ident(&self.parse_str(']'));
- ty::BrNamed(def, ident.name)
+ let def = self.parse_def();
+ let name = token::intern(&self.parse_str(']'));
+ ty::BrNamed(def, name)
}
'f' => {
let id = self.parse_u32();
}
'B' => {
assert_eq!(self.next(), '[');
- // this is the wrong NodeId, but `param_id` is only accessed
- // by the receiver-matching code in collect, which won't
- // be going down this code path, and anyway I will kill it
- // the moment wfcheck becomes the standard.
- let node_id = self.parse_uint() as ast::NodeId;
- assert_eq!(self.next(), '|');
+ let def_id = self.parse_def();
let space = self.parse_param_space();
assert_eq!(self.next(), '|');
let index = self.parse_u32();
assert_eq!(self.next(), '|');
- let nm = token::str_to_ident(&self.parse_str(']'));
+ let name = token::intern(&self.parse_str(']'));
ty::ReEarlyBound(ty::EarlyBoundRegion {
- param_id: node_id,
+ def_id: def_id,
space: space,
index: index,
- name: nm.name
+ name: name
})
}
'f' => {
}
pub fn parse_trait_ref(&mut self) -> ty::TraitRef<'tcx> {
- let def = self.parse_def(NominalType);
+ let def = self.parse_def();
let substs = self.tcx.mk_substs(self.parse_substs());
ty::TraitRef {def_id: def, substs: substs}
}
'c' => return tcx.types.char,
't' => {
assert_eq!(self.next(), '[');
- let did = self.parse_def(NominalType);
+ let did = self.parse_def();
let substs = self.parse_substs();
assert_eq!(self.next(), ']');
let def = self.tcx.lookup_adt_def(did);
return tcx.mk_tup(params);
}
'F' => {
- let def_id = self.parse_def(NominalType);
+ let def_id = self.parse_def();
return tcx.mk_fn(Some(def_id), tcx.mk_bare_fn(self.parse_bare_fn_ty()));
}
'G' => {
// we return it (modulo closure types, see below). But if not, then we
// jump to offset 123 and read the type from there.
- let pos = self.parse_hex();
- assert_eq!(self.next(), ':');
- let len = self.parse_hex();
- assert_eq!(self.next(), '#');
- let key = ty::CReaderCacheKey {cnum: self.krate, pos: pos, len: len };
+ let pos = self.parse_vuint();
+ let key = ty::CReaderCacheKey { cnum: self.krate, pos: pos };
match tcx.rcache.borrow().get(&key).cloned() {
Some(tt) => {
// If there is a closure buried in the type some where, then we
return tt;
}
'\"' => {
- let _ = self.parse_def(TypeWithId);
+ let _ = self.parse_def();
let inner = self.parse_ty();
inner
}
'a' => {
assert_eq!(self.next(), '[');
- let did = self.parse_def(NominalType);
+ let did = self.parse_def();
let substs = self.parse_substs();
assert_eq!(self.next(), ']');
let def = self.tcx.lookup_adt_def(did);
}
'k' => {
assert_eq!(self.next(), '[');
- let did = self.parse_def(ClosureSource);
+ let did = self.parse_def();
let substs = self.parse_substs();
let mut tys = vec![];
while self.peek() != '.' {
ty::TypeAndMut { ty: self.parse_ty(), mutbl: m }
}
- fn parse_def(&mut self, source: DefIdSource) -> DefId {
+ fn parse_def(&mut self) -> DefId {
let def_id = parse_defid(self.scan(|c| c == '|'));
- return (self.conv_def_id)(source, def_id);
+ return (self.conv_def_id)(def_id);
}
fn parse_uint(&mut self) -> usize {
subst::ParamSpace::from_uint(self.parse_uint())
}
- fn parse_hex(&mut self) -> usize {
- let mut n = 0;
- loop {
- let cur = self.peek();
- if (cur < '0' || cur > '9') && (cur < 'a' || cur > 'f') { return n; }
- self.pos = self.pos + 1;
- n *= 16;
- if '0' <= cur && cur <= '9' {
- n += (cur as usize) - ('0' as usize);
- } else { n += 10 + (cur as usize) - ('a' as usize); }
- };
- }
-
fn parse_abi_set(&mut self) -> abi::Abi {
assert_eq!(self.next(), '[');
let bytes = self.scan(|c| c == ']');
'p' => ty::Binder(self.parse_projection_predicate()).to_predicate(),
'w' => ty::Predicate::WellFormed(self.parse_ty()),
'O' => {
- let def_id = self.parse_def(NominalType);
+ let def_id = self.parse_def();
assert_eq!(self.next(), '|');
ty::Predicate::ObjectSafe(def_id)
}
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy {
trait_ref: self.parse_trait_ref(),
- item_name: token::str_to_ident(&self.parse_str('|')).name,
+ item_name: token::intern(&self.parse_str('|')),
},
ty: self.parse_ty(),
}
pub fn parse_type_param_def(&mut self) -> ty::TypeParameterDef<'tcx> {
let name = self.parse_name(':');
- let def_id = self.parse_def(NominalType);
+ let def_id = self.parse_def();
let space = self.parse_param_space();
assert_eq!(self.next(), '|');
let index = self.parse_u32();
assert_eq!(self.next(), '|');
- let default_def_id = self.parse_def(NominalType);
+ let default_def_id = self.parse_def();
let default = self.parse_opt(|this| this.parse_ty());
let object_lifetime_default = self.parse_object_lifetime_default();
pub fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
let name = self.parse_name(':');
- let def_id = self.parse_def(NominalType);
+ let def_id = self.parse_def();
let space = self.parse_param_space();
assert_eq!(self.next(), '|');
let index = self.parse_u32();
let def_num = match str::from_utf8(def_part).ok().and_then(|s| {
s.parse::<usize>().ok()
}) {
- Some(dn) => dn as ast::NodeId,
+ Some(dn) => dn,
None => panic!("internal error: parse_defid: id expected, found {:?}",
def_part)
};
- DefId { krate: crate_num, node: def_num }
+ let index = DefIndex::new(def_num);
+ DefId { krate: crate_num, index: index }
}
fn parse_unsafety(c: char) -> hir::Unsafety {
#![allow(non_camel_case_types)]
use std::cell::RefCell;
+use std::io::Cursor;
use std::io::prelude::*;
use middle::def_id::DefId;
use rustc_front::hir;
use syntax::abi::Abi;
+use syntax::ast;
use syntax::diagnostic::SpanHandler;
-use rbml::writer::Encoder;
+use rbml::writer::{self, Encoder};
macro_rules! mywrite { ($w:expr, $($arg:tt)*) => ({ write!($w.writer, $($arg)*); }) }
// Extra parameters are for converting to/from def_ids in the string rep.
// Whatever format you choose should not contain pipe characters.
pub struct ty_abbrev {
- s: String
+ s: Vec<u8>
}
pub type abbrev_map<'tcx> = RefCell<FnvHashMap<Ty<'tcx>, ty_abbrev>>;
pub fn enc_ty<'a, 'tcx>(w: &mut Encoder, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx>) {
match cx.abbrevs.borrow_mut().get(&t) {
- Some(a) => { w.writer.write_all(a.s.as_bytes()); return; }
+ Some(a) => { w.writer.write_all(&a.s); return; }
None => {}
}
ty::TyChar => mywrite!(w, "c"),
ty::TyInt(t) => {
match t {
- hir::TyIs => mywrite!(w, "is"),
- hir::TyI8 => mywrite!(w, "MB"),
- hir::TyI16 => mywrite!(w, "MW"),
- hir::TyI32 => mywrite!(w, "ML"),
- hir::TyI64 => mywrite!(w, "MD")
+ ast::TyIs => mywrite!(w, "is"),
+ ast::TyI8 => mywrite!(w, "MB"),
+ ast::TyI16 => mywrite!(w, "MW"),
+ ast::TyI32 => mywrite!(w, "ML"),
+ ast::TyI64 => mywrite!(w, "MD")
}
}
ty::TyUint(t) => {
match t {
- hir::TyUs => mywrite!(w, "us"),
- hir::TyU8 => mywrite!(w, "Mb"),
- hir::TyU16 => mywrite!(w, "Mw"),
- hir::TyU32 => mywrite!(w, "Ml"),
- hir::TyU64 => mywrite!(w, "Md")
+ ast::TyUs => mywrite!(w, "us"),
+ ast::TyU8 => mywrite!(w, "Mb"),
+ ast::TyU16 => mywrite!(w, "Mw"),
+ ast::TyU32 => mywrite!(w, "Ml"),
+ ast::TyU64 => mywrite!(w, "Md")
}
}
ty::TyFloat(t) => {
match t {
- hir::TyF32 => mywrite!(w, "Mf"),
- hir::TyF64 => mywrite!(w, "MF"),
+ ast::TyF32 => mywrite!(w, "Mf"),
+ ast::TyF64 => mywrite!(w, "MF"),
}
}
ty::TyEnum(def, substs) => {
let end = w.mark_stable_position();
let len = end - pos;
- fn estimate_sz(u: u64) -> u64 {
- let mut n = u;
- let mut len = 0;
- while n != 0 { len += 1; n = n >> 4; }
- return len;
- }
- let abbrev_len = 3 + estimate_sz(pos) + estimate_sz(len);
- if abbrev_len < len {
- // I.e. it's actually an abbreviation.
- cx.abbrevs.borrow_mut().insert(t, ty_abbrev {
- s: format!("#{:x}:{:x}#", pos, len)
- });
- }
+
+ let buf: &mut [u8] = &mut [0; 16]; // vuint < 15 bytes
+ let mut abbrev = Cursor::new(buf);
+ abbrev.write_all(b"#");
+ writer::write_vuint(&mut abbrev, pos as usize);
+
+ cx.abbrevs.borrow_mut().insert(t, ty_abbrev {
+ s: if abbrev.position() < len {
+ abbrev.get_ref()[..abbrev.position() as usize].to_owned()
+ } else {
+ // if the abbreviation is longer than the real type,
+ // don't use #-notation. However, insert it here so
+ // other won't have to `mark_stable_position`
+ w.writer.get_ref()[pos as usize..end as usize].to_owned()
+ }
+ });
}
fn enc_mutability(w: &mut Encoder, mt: hir::Mutability) {
}
ty::ReEarlyBound(ref data) => {
mywrite!(w, "B[{}|{}|{}|{}]",
- data.param_id,
+ (cx.ds)(data.def_id),
data.space.to_uint(),
data.index,
data.name);
}
}
+/// If a type in the AST is a primitive type, return the ty::Ty corresponding
+/// to it.
pub fn ast_ty_to_prim_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ast_ty: &ast::Ty)
-> Option<Ty<'tcx>> {
if let ast::TyPath(None, ref path) = ast_ty.node {
use metadata::encoder as e;
use metadata::inline::{InlinedItem, InlinedItemRef};
use metadata::tydecode;
-use metadata::tydecode::{DefIdSource, NominalType, TypeWithId};
-use metadata::tydecode::{RegionParameter, ClosureSource};
use metadata::tyencode;
use middle::ty::adjustment;
use middle::ty::cast;
use middle::check_const::ConstQualif;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::privacy::{AllPublic, LastMod};
use middle::region;
use middle::subst;
-use middle::subst::VecPerParamSpace;
use middle::ty::{self, Ty};
use syntax::{ast, ast_util, codemap};
+use syntax::ast::NodeIdAssigner;
use syntax::codemap::Span;
use syntax::ptr::P;
#[cfg(test)] use std::io::Cursor;
#[cfg(test)] use syntax::parse;
+#[cfg(test)] use syntax::ast::NodeId;
#[cfg(test)] use rustc_front::print::pprust;
-#[cfg(test)] use rustc_front::lowering::lower_item;
+#[cfg(test)] use rustc_front::lowering::{lower_item, LoweringContext};
struct DecodeContext<'a, 'b, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
fn tr(&self, dcx: &DecodeContext) -> Self;
}
-trait tr_intern {
- fn tr_intern(&self, dcx: &DecodeContext) -> DefId;
-}
-
// ______________________________________________________________________
// Top-level methods.
pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
tcx: &ty::ctxt<'tcx>,
path: Vec<ast_map::PathElem>,
- par_doc: rbml::Doc)
- -> Result<&'tcx InlinedItem, Vec<ast_map::PathElem>> {
+ def_path: ast_map::DefPath,
+ par_doc: rbml::Doc,
+ orig_did: DefId)
+ -> Result<&'tcx InlinedItem, (Vec<ast_map::PathElem>,
+ ast_map::DefPath)> {
match par_doc.opt_child(c::tag_ast) {
- None => Err(path),
+ None => Err((path, def_path)),
Some(ast_doc) => {
let mut path_as_str = None;
debug!("> Decoding inlined fn: {:?}::?",
last_filemap_index: Cell::new(0)
};
let raw_ii = decode_ast(ast_doc);
- let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, raw_ii, dcx);
+ let ii = ast_map::map_decoded_item(&dcx.tcx.map, path, def_path, raw_ii, dcx);
- let ident = match *ii {
- InlinedItem::Item(ref i) => i.ident,
- InlinedItem::Foreign(ref i) => i.ident,
- InlinedItem::TraitItem(_, ref ti) => ti.ident,
- InlinedItem::ImplItem(_, ref ii) => ii.ident
+ let name = match *ii {
+ InlinedItem::Item(ref i) => i.name,
+ InlinedItem::Foreign(ref i) => i.name,
+ InlinedItem::TraitItem(_, ref ti) => ti.name,
+ InlinedItem::ImplItem(_, ref ii) => ii.name
};
- debug!("Fn named: {}", ident);
+ debug!("Fn named: {}", name);
debug!("< Decoded inlined fn: {}::{}",
path_as_str.unwrap(),
- ident);
+ name);
region::resolve_inlined_item(&tcx.sess, &tcx.region_maps, ii);
decode_side_tables(dcx, ast_doc);
+ copy_item_types(dcx, ii, orig_did);
match *ii {
InlinedItem::Item(ref i) => {
debug!(">>> DECODED ITEM >>>\n{}\n<<< DECODED ITEM <<<",
/// be inlined. Note that even when the inlined function is referencing itself recursively, we
/// would want `tr_def_id` for that reference--- conceptually the function calls the original,
/// non-inlined version, and trans deals with linking that recursive call to the inlined copy.
- ///
- /// However, there are a *few* cases where def-ids are used but we know that the thing being
- /// referenced is in fact *internal* to the item being inlined. In those cases, you should use
- /// `tr_intern_def_id()` below.
pub fn tr_def_id(&self, did: DefId) -> DefId {
-
decoder::translate_def_id(self.cdata, did)
}
- /// Translates an INTERNAL def-id, meaning a def-id that is
- /// known to refer to some part of the item currently being
- /// inlined. In that case, we want to convert the def-id to
- /// refer to the current crate and to the new, inlined node-id.
- pub fn tr_intern_def_id(&self, did: DefId) -> DefId {
- assert_eq!(did.krate, LOCAL_CRATE);
- DefId { krate: LOCAL_CRATE, node: self.tr_id(did.node) }
- }
-
/// Translates a `Span` from an extern crate to the corresponding `Span`
/// within the local crate's codemap. `creader::import_codemap()` will
/// already have allocated any additionally needed FileMaps in the local
}
}
-impl tr_intern for DefId {
- fn tr_intern(&self, dcx: &DecodeContext) -> DefId {
- dcx.tr_intern_def_id(*self)
- }
-}
-
impl tr for DefId {
fn tr(&self, dcx: &DecodeContext) -> DefId {
dcx.tr_def_id(*self)
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
def::DefAssociatedConst(did) => def::DefAssociatedConst(did.tr(dcx)),
- def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
+ def::DefLocal(_, nid) => {
+ let nid = dcx.tr_id(nid);
+ let did = dcx.tcx.map.local_def_id(nid);
+ def::DefLocal(did, nid)
+ }
def::DefVariant(e_did, v_did, is_s) => {
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
},
def::DefPrimTy(p) => def::DefPrimTy(p),
def::DefTyParam(s, index, def_id, n) => def::DefTyParam(s, index, def_id.tr(dcx), n),
def::DefUse(did) => def::DefUse(did.tr(dcx)),
- def::DefUpvar(nid1, index, nid2) => {
- def::DefUpvar(dcx.tr_id(nid1), index, dcx.tr_id(nid2))
+ def::DefUpvar(_, nid1, index, nid2) => {
+ let nid1 = dcx.tr_id(nid1);
+ let nid2 = dcx.tr_id(nid2);
+ let did1 = dcx.tcx.map.local_def_id(nid1);
+ def::DefUpvar(did1, nid1, index, nid2)
}
def::DefStruct(did) => def::DefStruct(did.tr(dcx)),
- def::DefRegion(nid) => def::DefRegion(dcx.tr_id(nid)),
def::DefLabel(nid) => def::DefLabel(dcx.tr_id(nid))
}
}
}
}
-pub fn encode_closure_kind(ebml_w: &mut Encoder, kind: ty::ClosureKind) {
- kind.encode(ebml_w).unwrap();
-}
-
pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) {
kind.encode(ebml_w).unwrap();
}
-pub trait vtable_decoder_helpers<'tcx> {
- fn read_vec_per_param_space<T, F>(&mut self, f: F) -> VecPerParamSpace<T> where
- F: FnMut(&mut Self) -> T;
-}
-
-impl<'tcx, 'a> vtable_decoder_helpers<'tcx> for reader::Decoder<'a> {
- fn read_vec_per_param_space<T, F>(&mut self, mut f: F) -> VecPerParamSpace<T> where
- F: FnMut(&mut reader::Decoder<'a>) -> T,
- {
- let types = self.read_to_vec(|this| Ok(f(this))).unwrap();
- let selfs = self.read_to_vec(|this| Ok(f(this))).unwrap();
- let fns = self.read_to_vec(|this| Ok(f(this))).unwrap();
- VecPerParamSpace::new(types, selfs, fns)
- }
-}
-
-// ___________________________________________________________________________
-//
-
-fn encode_vec_per_param_space<T, F>(rbml_w: &mut Encoder,
- v: &subst::VecPerParamSpace<T>,
- mut f: F) where
- F: FnMut(&mut Encoder, &T),
-{
- for &space in &subst::ParamSpace::all() {
- rbml_w.emit_from_vec(v.get_slice(space),
- |rbml_w, n| Ok(f(rbml_w, n))).unwrap();
- }
-}
-
// ______________________________________________________________________
// Encoding and decoding the side tables
}
trait rbml_writer_helpers<'tcx> {
- fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
- closure_type: &ty::ClosureTy<'tcx>);
fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region);
fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]);
- fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
- type_param_def: &ty::TypeParameterDef<'tcx>);
- fn emit_region_param_def(&mut self, ecx: &e::EncodeContext,
- region_param_def: &ty::RegionParameterDef);
fn emit_predicate<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
predicate: &ty::Predicate<'tcx>);
fn emit_trait_ref<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
ty: &ty::TraitRef<'tcx>);
- fn emit_type_scheme<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
- type_scheme: ty::TypeScheme<'tcx>);
fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
substs: &subst::Substs<'tcx>);
fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>,
}
impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
- fn emit_closure_type<'b>(&mut self,
- ecx: &e::EncodeContext<'b, 'tcx>,
- closure_type: &ty::ClosureTy<'tcx>) {
- self.emit_opaque(|this| {
- Ok(e::write_closure_type(ecx, this, closure_type))
- });
- }
-
fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) {
self.emit_opaque(|this| Ok(e::write_region(ecx, this, r)));
}
self.emit_opaque(|this| Ok(e::write_trait_ref(ecx, this, trait_ref)));
}
- fn emit_type_param_def<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
- type_param_def: &ty::TypeParameterDef<'tcx>) {
- self.emit_opaque(|this| {
- Ok(tyencode::enc_type_param_def(this,
- &ecx.ty_str_ctxt(),
- type_param_def))
- });
- }
- fn emit_region_param_def(&mut self, ecx: &e::EncodeContext,
- region_param_def: &ty::RegionParameterDef) {
- self.emit_opaque(|this| {
- Ok(tyencode::enc_region_param_def(this,
- &ecx.ty_str_ctxt(),
- region_param_def))
- });
- }
fn emit_predicate<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>,
predicate: &ty::Predicate<'tcx>) {
self.emit_opaque(|this| {
});
}
- fn emit_type_scheme<'b>(&mut self,
- ecx: &e::EncodeContext<'b, 'tcx>,
- type_scheme: ty::TypeScheme<'tcx>) {
- use serialize::Encoder;
-
- self.emit_struct("TypeScheme", 2, |this| {
- this.emit_struct_field("generics", 0, |this| {
- this.emit_struct("Generics", 2, |this| {
- this.emit_struct_field("types", 0, |this| {
- Ok(encode_vec_per_param_space(
- this, &type_scheme.generics.types,
- |this, def| this.emit_type_param_def(ecx, def)))
- });
- this.emit_struct_field("regions", 1, |this| {
- Ok(encode_vec_per_param_space(
- this, &type_scheme.generics.regions,
- |this, def| this.emit_region_param_def(ecx, def)))
- })
- })
- });
- this.emit_struct_field("ty", 1, |this| {
- Ok(this.emit_ty(ecx, type_scheme.ty))
- })
- });
- }
-
fn emit_existential_bounds<'b>(&mut self, ecx: &e::EncodeContext<'b,'tcx>,
bounds: &ty::ExistentialBounds<'tcx>) {
self.emit_opaque(|this| Ok(tyencode::enc_existential_bounds(this,
rbml_w.tag(c::tag_table_upvar_capture_map, |rbml_w| {
rbml_w.id(id);
- let var_id = freevar.def.def_id().node;
+ let var_id = freevar.def.var_id();
let upvar_id = ty::UpvarId {
var_id: var_id,
closure_expr_id: id
}
}
- let lid = DefId { krate: LOCAL_CRATE, node: id };
- if let Some(type_scheme) = tcx.tcache.borrow().get(&lid) {
- rbml_w.tag(c::tag_table_tcache, |rbml_w| {
- rbml_w.id(id);
- rbml_w.emit_type_scheme(ecx, type_scheme.clone());
- })
- }
-
- if let Some(type_param_def) = tcx.ty_param_defs.borrow().get(&id) {
- rbml_w.tag(c::tag_table_param_defs, |rbml_w| {
- rbml_w.id(id);
- rbml_w.emit_type_param_def(ecx, type_param_def)
- })
- }
-
let method_call = ty::MethodCall::expr(id);
if let Some(method) = tcx.tables.borrow().method_map.get(&method_call) {
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
})
}
- if let Some(closure_type) = tcx.tables.borrow().closure_tys.get(&DefId::local(id)) {
- rbml_w.tag(c::tag_table_closure_tys, |rbml_w| {
- rbml_w.id(id);
- rbml_w.emit_closure_type(ecx, closure_type);
- })
- }
-
- if let Some(closure_kind) = tcx.tables.borrow().closure_kinds.get(&DefId::local(id)) {
- rbml_w.tag(c::tag_table_closure_kinds, |rbml_w| {
- rbml_w.id(id);
- encode_closure_kind(rbml_w, *closure_kind)
- })
- }
-
if let Some(cast_kind) = tcx.cast_kinds.borrow().get(&id) {
rbml_w.tag(c::tag_table_cast_kinds, |rbml_w| {
rbml_w.id(id);
-> ty::TraitRef<'tcx>;
fn read_poly_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::PolyTraitRef<'tcx>;
- fn read_type_param_def<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
- -> ty::TypeParameterDef<'tcx>;
- fn read_region_param_def(&mut self, dcx: &DecodeContext)
- -> ty::RegionParameterDef;
fn read_predicate<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::Predicate<'tcx>;
- fn read_type_scheme<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
- -> ty::TypeScheme<'tcx>;
fn read_existential_bounds<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::ExistentialBounds<'tcx>;
fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> adjustment::AutoAdjustment<'tcx>;
fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> cast::CastKind;
- fn read_closure_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
- -> ty::ClosureKind;
- fn read_closure_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
- -> ty::ClosureTy<'tcx>;
fn read_auto_deref_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> adjustment::AutoDerefRef<'tcx>;
fn read_autoref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> adjustment::AutoRef<'tcx>;
fn convert_def_id(&mut self,
dcx: &DecodeContext,
- source: DefIdSource,
did: DefId)
-> DefId;
self.read_opaque(|_, doc| {
Ok(
tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc,
- &mut |_, id| decoder::translate_def_id(cdata, id))
+ &mut |id| decoder::translate_def_id(cdata, id))
.parse_ty())
}).unwrap()
}
self.read_opaque(|_, doc| {
Ok(
tydecode::TyDecoder::with_doc(tcx, cdata.cnum, doc,
- &mut |_, id| decoder::translate_def_id(cdata, id))
+ &mut |id| decoder::translate_def_id(cdata, id))
.parse_substs())
}).unwrap()
}
Ok(op(
&mut tydecode::TyDecoder::with_doc(
dcx.tcx, dcx.cdata.cnum, doc,
- &mut |s, a| this.convert_def_id(dcx, s, a))))
+ &mut |a| this.convert_def_id(dcx, a))))
}).unwrap();
fn type_string(doc: rbml::Doc) -> String {
ty::Binder(self.read_ty_encoded(dcx, |decoder| decoder.parse_trait_ref()))
}
- fn read_type_param_def<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
- -> ty::TypeParameterDef<'tcx> {
- self.read_ty_encoded(dcx, |decoder| decoder.parse_type_param_def())
- }
- fn read_region_param_def(&mut self, dcx: &DecodeContext)
- -> ty::RegionParameterDef {
- self.read_ty_encoded(dcx, |decoder| decoder.parse_region_param_def())
- }
fn read_predicate<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::Predicate<'tcx>
{
self.read_ty_encoded(dcx, |decoder| decoder.parse_predicate())
}
- fn read_type_scheme<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
- -> ty::TypeScheme<'tcx> {
- self.read_struct("TypeScheme", 3, |this| {
- Ok(ty::TypeScheme {
- generics: this.read_struct_field("generics", 0, |this| {
- this.read_struct("Generics", 2, |this| {
- Ok(ty::Generics {
- types:
- this.read_struct_field("types", 0, |this| {
- Ok(this.read_vec_per_param_space(
- |this| this.read_type_param_def(dcx)))
- }).unwrap(),
-
- regions:
- this.read_struct_field("regions", 1, |this| {
- Ok(this.read_vec_per_param_space(
- |this| this.read_region_param_def(dcx)))
- }).unwrap(),
- })
- })
- }).unwrap(),
- ty: this.read_struct_field("ty", 1, |this| {
- Ok(this.read_ty(dcx))
- }).unwrap()
- })
- }).unwrap()
- }
-
fn read_existential_bounds<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
-> ty::ExistentialBounds<'tcx>
{
-> subst::Substs<'tcx> {
self.read_opaque(|this, doc| {
Ok(tydecode::TyDecoder::with_doc(dcx.tcx, dcx.cdata.cnum, doc,
- &mut |s, a| this.convert_def_id(dcx, s, a))
+ &mut |a| this.convert_def_id(dcx, a))
.parse_substs())
}).unwrap()
}
Decodable::decode(self).unwrap()
}
- fn read_closure_kind<'b, 'c>(&mut self, _dcx: &DecodeContext<'b, 'c, 'tcx>)
- -> ty::ClosureKind
- {
- Decodable::decode(self).unwrap()
- }
-
- fn read_closure_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
- -> ty::ClosureTy<'tcx>
- {
- self.read_ty_encoded(dcx, |decoder| decoder.parse_closure_ty())
- }
-
/// Converts a def-id that appears in a type. The correct
/// translation will depend on what kind of def-id this is.
/// This is a subtle point: type definitions are not
/// def-ids so that all these distinctions were unnecessary.
fn convert_def_id(&mut self,
dcx: &DecodeContext,
- source: tydecode::DefIdSource,
did: DefId)
-> DefId {
- let r = match source {
- NominalType | TypeWithId | RegionParameter => dcx.tr_def_id(did),
- ClosureSource => dcx.tr_intern_def_id(did)
- };
- debug!("convert_def_id(source={:?}, did={:?})={:?}", source, did, r);
+ let r = dcx.tr_def_id(did);
+ debug!("convert_def_id(did={:?})={:?}", did, r);
return r;
}
}
let ub = val_dsr.read_upvar_capture(dcx);
dcx.tcx.tables.borrow_mut().upvar_capture_map.insert(upvar_id, ub);
}
- c::tag_table_tcache => {
- let type_scheme = val_dsr.read_type_scheme(dcx);
- let lid = DefId { krate: LOCAL_CRATE, node: id };
- dcx.tcx.register_item_type(lid, type_scheme);
- }
- c::tag_table_param_defs => {
- let bounds = val_dsr.read_type_param_def(dcx);
- dcx.tcx.ty_param_defs.borrow_mut().insert(id, bounds);
- }
c::tag_table_method_map => {
let (autoderef, method) = val_dsr.read_method_callee(dcx);
let method_call = ty::MethodCall {
val_dsr.read_auto_adjustment(dcx);
dcx.tcx.tables.borrow_mut().adjustments.insert(id, adj);
}
- c::tag_table_closure_tys => {
- let closure_ty =
- val_dsr.read_closure_ty(dcx);
- dcx.tcx.tables.borrow_mut().closure_tys.insert(DefId::local(id),
- closure_ty);
- }
- c::tag_table_closure_kinds => {
- let closure_kind =
- val_dsr.read_closure_kind(dcx);
- dcx.tcx.tables.borrow_mut().closure_kinds.insert(DefId::local(id),
- closure_kind);
- }
c::tag_table_cast_kinds => {
let cast_kind =
val_dsr.read_cast_kind(dcx);
}
}
+// copy the tcache entries from the original item to the new
+// inlined item
+fn copy_item_types(dcx: &DecodeContext, ii: &InlinedItem, orig_did: DefId) {
+ fn copy_item_type(dcx: &DecodeContext,
+ inlined_id: ast::NodeId,
+ remote_did: DefId) {
+ let inlined_did = dcx.tcx.map.local_def_id(inlined_id);
+ dcx.tcx.register_item_type(inlined_did,
+ dcx.tcx.lookup_item_type(remote_did));
+
+ }
+ // copy the entry for the item itself
+ let item_node_id = match ii {
+ &InlinedItem::Item(ref i) => i.id,
+ &InlinedItem::TraitItem(_, ref ti) => ti.id,
+ &InlinedItem::ImplItem(_, ref ii) => ii.id,
+ &InlinedItem::Foreign(ref fi) => fi.id
+ };
+ copy_item_type(dcx, item_node_id, orig_did);
+
+ // copy the entries of inner items
+ if let &InlinedItem::Item(ref item) = ii {
+ match item.node {
+ hir::ItemEnum(ref def, _) => {
+ let orig_def = dcx.tcx.lookup_adt_def(orig_did);
+ for (i_variant, orig_variant) in
+ def.variants.iter().zip(orig_def.variants.iter())
+ {
+ debug!("astencode: copying variant {:?} => {:?}",
+ orig_variant.did, i_variant.node.data.id());
+ copy_item_type(dcx, i_variant.node.data.id(), orig_variant.did);
+ }
+ }
+ hir::ItemStruct(ref def, _) => {
+ if !def.is_struct() {
+ let ctor_did = dcx.tcx.lookup_adt_def(orig_did)
+ .struct_variant().did;
+ debug!("astencode: copying ctor {:?} => {:?}", ctor_did,
+ def.id());
+ copy_item_type(dcx, def.id(), ctor_did);
+ }
+ }
+ _ => {}
+ }
+ }
+}
+
// ______________________________________________________________________
// Testing of astencode_gen
fn parse_sess(&self) -> &parse::ParseSess { self }
}
+#[cfg(test)]
+struct FakeNodeIdAssigner;
+
+#[cfg(test)]
+// It should go without saying that this may give unexpected results. Avoid
+// lowering anything which needs new nodes.
+impl NodeIdAssigner for FakeNodeIdAssigner {
+ fn next_node_id(&self) -> NodeId {
+ 0
+ }
+
+ fn peek_node_id(&self) -> NodeId {
+ 0
+ }
+}
+
#[cfg(test)]
fn mk_ctxt() -> parse::ParseSess {
parse::ParseSess::new()
#[test]
fn test_basic() {
let cx = mk_ctxt();
- roundtrip(lower_item("e_item!(&cx,
+ let fnia = FakeNodeIdAssigner;
+ let lcx = LoweringContext::new(&fnia, None);
+ roundtrip(lower_item(&lcx, "e_item!(&cx,
fn foo() {}
).unwrap()));
}
#[test]
fn test_smalltalk() {
let cx = mk_ctxt();
- roundtrip(lower_item("e_item!(&cx,
+ let fnia = FakeNodeIdAssigner;
+ let lcx = LoweringContext::new(&fnia, None);
+ roundtrip(lower_item(&lcx, "e_item!(&cx,
fn foo() -> isize { 3 + 4 } // first smalltalk program ever executed.
).unwrap()));
}
#[test]
fn test_more() {
let cx = mk_ctxt();
- roundtrip(lower_item("e_item!(&cx,
+ let fnia = FakeNodeIdAssigner;
+ let lcx = LoweringContext::new(&fnia, None);
+ roundtrip(lower_item(&lcx, "e_item!(&cx,
fn foo(x: usize, y: usize) -> usize {
let z = x + y;
return z;
return alist {eq_fn: eq_int, data: Vec::new()};
}
).unwrap();
- let hir_item = lower_item(&item);
+ let fnia = FakeNodeIdAssigner;
+ let lcx = LoweringContext::new(&fnia, None);
+ let hir_item = lower_item(&lcx, &item);
let item_in = InlinedItemRef::Item(&hir_item);
let item_out = simplify_ast(item_in);
- let item_exp = InlinedItem::Item(lower_item("e_item!(&cx,
+ let item_exp = InlinedItem::Item(lower_item(&lcx, "e_item!(&cx,
fn new_int_alist<B>() -> alist<isize, B> {
return alist {eq_fn: eq_int, data: Vec::new()};
}
}
hir::ExprBreak(label) => {
- let loop_scope = self.find_scope(expr, label.map(|l| l.node));
+ let loop_scope = self.find_scope(expr, label.map(|l| l.node.name));
let b = self.add_ast_node(expr.id, &[pred]);
self.add_exiting_edge(expr, b,
loop_scope, loop_scope.break_index);
}
hir::ExprAgain(label) => {
- let loop_scope = self.find_scope(expr, label.map(|l| l.node));
+ let loop_scope = self.find_scope(expr, label.map(|l| l.node.name));
let a = self.add_ast_node(expr.id, &[pred]);
self.add_exiting_edge(expr, a,
loop_scope, loop_scope.continue_index);
self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
}
- hir::ExprBox(Some(ref l), ref r) |
hir::ExprIndex(ref l, ref r) |
hir::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier
self.straightline(expr, pred, [l, r].iter().map(|&e| &**e))
}
- hir::ExprBox(None, ref e) |
+ hir::ExprBox(ref e) |
hir::ExprAddrOf(_, ref e) |
hir::ExprCast(ref e, _) |
hir::ExprUnary(_, ref e) |
- hir::ExprParen(ref e) |
hir::ExprField(ref e, _) |
hir::ExprTupField(ref e, _) => {
self.straightline(expr, pred, Some(&**e).into_iter())
fn find_scope(&self,
expr: &hir::Expr,
- label: Option<ast::Ident>) -> LoopScope {
+ label: Option<ast::Name>) -> LoopScope {
if label.is_none() {
return *self.loop_scopes.last().unwrap();
}
use rustc_front::hir;
use syntax::ast;
use syntax::codemap::Span;
+use syntax::feature_gate::UnstableFeatures;
use rustc_front::visit::{self, FnKind, Visitor};
use std::collections::hash_map::Entry;
if mode == Mode::ConstFn {
for arg in &fd.inputs {
match arg.pat.node {
+ hir::PatWild(_) => {}
hir::PatIdent(hir::BindByValue(hir::MutImmutable), _, None) => {}
_ => {
span_err!(self.tcx.sess, arg.pat.span, E0022,
ty::TyUint(_) | ty::TyInt(_) if div_or_rem => {
if !self.qualif.intersects(ConstQualif::NOT_CONST) {
match const_eval::eval_const_expr_partial(
- self.tcx, ex, ExprTypeChecked) {
+ self.tcx, ex, ExprTypeChecked, None) {
Ok(_) => {}
Err(msg) => {
- span_err!(self.tcx.sess, msg.span, E0020,
- "{} in a constant expression",
- msg.description())
+ self.tcx.sess.add_lint(::lint::builtin::CONST_ERR, ex.id,
+ msg.span,
+ msg.description().into_owned())
}
}
}
if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
outer = outer | ConstQualif::NOT_CONST;
if self.mode != Mode::Var {
- self.tcx.sess.span_err(ex.span,
- "cannot borrow a constant which contains \
- interior mutability, create a static instead");
+ span_err!(self.tcx.sess, ex.span, E0492,
+ "cannot borrow a constant which contains \
+ interior mutability, create a static instead");
}
}
// If the reference has to be 'static, avoid in-place initialization
ty::TyEnum(def, _) if def.has_dtor() => {
v.add_qualif(ConstQualif::NEEDS_DROP);
if v.mode != Mode::Var {
- v.tcx.sess.span_err(e.span,
- &format!("{}s are not allowed to have destructors",
- v.msg()));
+ span_err!(v.tcx.sess, e.span, E0493,
+ "{}s are not allowed to have destructors",
+ v.msg());
}
}
_ => {}
"user-defined operators are not allowed in {}s", v.msg());
}
}
- hir::ExprBox(..) |
- hir::ExprUnary(hir::UnUniq, _) => {
+ hir::ExprBox(_) => {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
span_err!(v.tcx.sess, e.span, E0010,
doesn't point to a constant");
}
}
- Some(def::DefLocal(_)) if v.mode == Mode::ConstFn => {
+ Some(def::DefLocal(..)) if v.mode == Mode::ConstFn => {
// Sadly, we can't determine whether the types are zero-sized.
v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
}
let mut callee = &**callee;
loop {
callee = match callee.node {
- hir::ExprParen(ref inner) => &**inner,
hir::ExprBlock(ref block) => match block.expr {
Some(ref tail) => &**tail,
None => break
if !is_const {
v.add_qualif(ConstQualif::NOT_CONST);
if v.mode != Mode::Var {
- span_err!(v.tcx.sess, e.span, E0015,
- "function calls in {}s are limited to \
- constant functions, \
- struct and enum constructors", v.msg());
+ fn span_limited_call_error(tcx: &ty::ctxt, span: Span, s: &str) {
+ span_err!(tcx.sess, span, E0015, "{}", s);
+ }
+
+ // FIXME(#24111) Remove this check when const fn stabilizes
+ if let UnstableFeatures::Disallow = v.tcx.sess.opts.unstable_features {
+ span_limited_call_error(&v.tcx, e.span,
+ &format!("function calls in {}s are limited to \
+ struct and enum constructors",
+ v.msg()));
+ v.tcx.sess.span_note(e.span,
+ "a limited form of compile-time function \
+ evaluation is available on a nightly \
+ compiler via `const fn`");
+ } else {
+ span_limited_call_error(&v.tcx, e.span,
+ &format!("function calls in {}s are limited \
+ to constant functions, \
+ struct and enum constructors",
+ v.msg()));
+ }
}
}
}
hir::ExprField(..) |
hir::ExprTupField(..) |
hir::ExprVec(_) |
- hir::ExprParen(..) |
hir::ExprTup(..) => {}
// Conditional control flow (possible to implement).
// Borrowed statics can specifically *only* have their address taken,
// not any number of other borrows such as borrowing fields, reading
// elements of an array, etc.
- self.tcx.sess.span_err(borrow_span,
- "cannot refer to the interior of another \
- static, use a constant instead");
+ span_err!(self.tcx.sess, borrow_span, E0494,
+ "cannot refer to the interior of another \
+ static, use a constant instead");
}
break;
}
use middle::ty;
use std::cmp::Ordering;
use std::fmt;
-use std::iter::{range_inclusive, FromIterator, IntoIterator, repeat};
-use std::slice;
+use std::iter::{FromIterator, IntoIterator, repeat};
use rustc_front::hir;
use rustc_front::hir::Pat;
use rustc_front::visit::{self, Visitor, FnKind};
use rustc_front::util as front_util;
+use rustc_back::slice;
use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
use syntax::ast_util;
let pat_ty = cx.tcx.pat_ty(p);
if let ty::TyEnum(edef, _) = pat_ty.sty {
let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
- if let Some(DefLocal(_)) = def {
+ if let Some(DefLocal(..)) = def {
if edef.variants.iter().any(|variant|
variant.name == ident.node.name
&& variant.kind() == VariantKind::Unit
fn check_for_static_nan(cx: &MatchCheckCtxt, pat: &Pat) {
front_util::walk_pat(pat, |p| {
if let hir::PatLit(ref expr) = p.node {
- match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked) {
+ match eval_const_expr_partial(cx.tcx, &**expr, ExprTypeChecked, None) {
Ok(ConstVal::Float(f)) if f.is_nan() => {
span_warn!(cx.tcx.sess, p.span, E0003,
"unmatchable NaN in pattern, \
Ok(_) => {}
Err(err) => {
- let subspan = p.span.lo <= err.span.lo && err.span.hi <= p.span.hi;
- cx.tcx.sess.span_err(err.span,
- &format!("constant evaluation error: {}",
- err.description()));
- if !subspan {
+ span_err!(cx.tcx.sess, err.span, E0471,
+ "constant evaluation error: {}",
+ err.description());
+ if !p.span.contains(err.span) {
cx.tcx.sess.span_note(p.span,
"in pattern here")
}
fn const_val_to_expr(value: &ConstVal) -> P<hir::Expr> {
let node = match value {
- &ConstVal::Bool(b) => hir::LitBool(b),
+ &ConstVal::Bool(b) => ast::LitBool(b),
_ => unreachable!()
};
P(hir::Expr {
ty::TyEnum(adt, _) | ty::TyStruct(adt, _) => {
let v = adt.variant_of_ctor(ctor);
- if let VariantKind::Dict = v.kind() {
+ if let VariantKind::Struct = v.kind() {
let field_pats: Vec<_> = v.fields.iter()
.zip(pats)
.filter(|&(_, ref pat)| pat.node != hir::PatWild(hir::PatWildSingle))
.map(|(field, pat)| Spanned {
span: DUMMY_SP,
node: hir::FieldPat {
- ident: ast::Ident::new(field.name),
+ name: field.name,
pat: pat,
is_shorthand: false,
}
ty::TyRef(_, ty::TypeAndMut { ty, .. }) => match ty.sty {
ty::TySlice(_) =>
- range_inclusive(0, max_slice_length).map(|length| Slice(length)).collect(),
+ (0..max_slice_length+1).map(|length| Slice(length)).collect(),
_ => vec![Single]
},
match left_ty.sty {
ty::TyArray(_, _) => vec!(Single),
_ => if slice.is_some() {
- range_inclusive(before.len() + after.len(), max_slice_length)
+ (before.len() + after.len()..max_slice_length+1)
.map(|length| Slice(length))
.collect()
} else {
let def_variant = adt.variant_of_def(def);
if variant.did == def_variant.did {
Some(variant.fields.iter().map(|sf| {
- match pattern_fields.iter().find(|f| f.node.ident.name == sf.name) {
+ match pattern_fields.iter().find(|f| f.node.name == sf.name) {
Some(ref f) => &*f.node.pat,
_ => DUMMY_WILD_PAT
}
impl<'a, 'v> Visitor<'v> for CheckNoAsm<'a> {
fn visit_expr(&mut self, e: &ast::Expr) {
match e.node {
- ast::ExprInlineAsm(_) => self.sess.span_err(e.span,
- "asm! is unsupported on this target"),
+ ast::ExprInlineAsm(_) => span_err!(self.sess, e.span, E0472,
+ "asm! is unsupported on this target"),
_ => {},
}
visit::walk_expr(self, e)
let mut recursion_visitor =
CheckItemRecursionVisitor::new(self, &variant.span);
recursion_visitor.populate_enum_discriminants(enum_def);
- recursion_visitor.visit_variant(variant, generics);
+ recursion_visitor.visit_variant(variant, generics, it.id);
}
}
}
let mut discriminant_map = self.discriminant_map.borrow_mut();
match enum_definition.variants.first() {
None => { return; }
- Some(variant) if discriminant_map.contains_key(&variant.node.id) => {
+ Some(variant) if discriminant_map.contains_key(&variant.node.data.id()) => {
return;
}
_ => {}
// Go through all the variants.
let mut variant_stack: Vec<ast::NodeId> = Vec::new();
for variant in enum_definition.variants.iter().rev() {
- variant_stack.push(variant.node.id);
+ variant_stack.push(variant.node.data.id());
// When we find an expression, every variant currently on the stack
// is affected by that expression.
if let Some(ref expr) = variant.node.disr_expr {
}
fn visit_enum_def(&mut self, enum_definition: &'ast hir::EnumDef,
- generics: &'ast hir::Generics) {
+ generics: &'ast hir::Generics, item_id: ast::NodeId, _: Span) {
self.populate_enum_discriminants(enum_definition);
- visit::walk_enum_def(self, enum_definition, generics);
+ visit::walk_enum_def(self, enum_definition, generics, item_id);
}
fn visit_variant(&mut self, variant: &'ast hir::Variant,
- _: &'ast hir::Generics) {
- let variant_id = variant.node.id;
+ _: &'ast hir::Generics, _: ast::NodeId) {
+ let variant_id = variant.node.data.id();
let maybe_expr;
if let Some(get_expr) = self.discriminant_map.borrow().get(&variant_id) {
// This is necessary because we need to let the `discriminant_map`
match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
Some(DefStatic(def_id, _)) |
Some(DefAssociatedConst(def_id)) |
- Some(DefConst(def_id)) if def_id.is_local() => {
- match self.ast_map.get(def_id.node) {
- ast_map::NodeItem(item) =>
- self.visit_item(item),
- ast_map::NodeTraitItem(item) =>
- self.visit_trait_item(item),
- ast_map::NodeImplItem(item) =>
- self.visit_impl_item(item),
- ast_map::NodeForeignItem(_) => {},
- _ => {
- self.sess.span_bug(
- e.span,
- &format!("expected item, found {}",
- self.ast_map.node_to_string(def_id.node)));
- }
+ Some(DefConst(def_id)) => {
+ if let Some(node_id) = self.ast_map.as_local_node_id(def_id) {
+ match self.ast_map.get(node_id) {
+ ast_map::NodeItem(item) =>
+ self.visit_item(item),
+ ast_map::NodeTraitItem(item) =>
+ self.visit_trait_item(item),
+ ast_map::NodeImplItem(item) =>
+ self.visit_impl_item(item),
+ ast_map::NodeForeignItem(_) => {},
+ _ => {
+ self.sess.span_bug(
+ e.span,
+ &format!("expected item, found {}",
+ self.ast_map.node_to_string(node_id)));
+ }
+ }
}
}
// For variants, we only want to check expressions that
// affect the specific variant used, but we need to check
// the whole enum definition to see what expression that
// might be (if any).
- Some(DefVariant(enum_id, variant_id, false)) if enum_id.is_local() => {
- if let hir::ItemEnum(ref enum_def, ref generics) =
- self.ast_map.expect_item(enum_id.local_id()).node {
- self.populate_enum_discriminants(enum_def);
- let variant = self.ast_map.expect_variant(variant_id.local_id());
- self.visit_variant(variant, generics);
- } else {
- self.sess.span_bug(e.span,
- "`check_static_recursion` found \
- non-enum in DefVariant");
+ Some(DefVariant(enum_id, variant_id, false)) => {
+ if let Some(enum_node_id) = self.ast_map.as_local_node_id(enum_id) {
+ if let hir::ItemEnum(ref enum_def, ref generics) =
+ self.ast_map.expect_item(enum_node_id).node
+ {
+ self.populate_enum_discriminants(enum_def);
+ let enum_id = self.ast_map.as_local_node_id(enum_id).unwrap();
+ let variant_id = self.ast_map.as_local_node_id(variant_id).unwrap();
+ let variant = self.ast_map.expect_variant(variant_id);
+ self.visit_variant(variant, generics, enum_id);
+ } else {
+ self.sess.span_bug(e.span,
+ "`check_static_recursion` found \
+ non-enum in DefVariant");
+ }
}
}
_ => ()
use metadata::csearch;
use metadata::inline::InlinedItem;
use middle::{astencode, def, infer, subst, traits};
-use middle::def_id::{DefId};
+use middle::def_id::DefId;
use middle::pat_util::def_to_path;
use middle::ty::{self, Ty};
use middle::astconv_util::ast_ty_to_prim_ty;
use util::num::ToPrimitive;
+use util::nodemap::NodeMap;
-use syntax::ast;
+use syntax::{ast, abi};
use rustc_front::hir::Expr;
use rustc_front::hir;
use rustc_front::visit::FnKind;
use std::num::wrapping::OverflowingOps;
use std::cmp::Ordering;
use std::collections::hash_map::Entry::Vacant;
+use std::mem::transmute;
use std::{i8, i16, i32, i64, u8, u16, u32, u64};
use std::rc::Rc;
fn variant_expr<'a>(variants: &'a [P<hir::Variant>], id: ast::NodeId)
-> Option<&'a Expr> {
for variant in variants {
- if variant.node.id == id {
+ if variant.node.data.id() == id {
return variant.node.disr_expr.as_ref().map(|e| &**e);
}
}
None
}
- if enum_def.is_local() {
- match tcx.map.find(enum_def.node) {
+ if let Some(enum_node_id) = tcx.map.as_local_node_id(enum_def) {
+ let variant_node_id = tcx.map.as_local_node_id(variant_def).unwrap();
+ match tcx.map.find(enum_node_id) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
- variant_expr(&variants[..], variant_def.node)
+ variant_expr(&variants[..], variant_node_id)
}
_ => None
},
Some(_) => None
}
} else {
- match tcx.extern_const_variants.borrow().get(&variant_def) {
- Some(&ast::DUMMY_NODE_ID) => return None,
- Some(&expr_id) => {
- return Some(tcx.map.expect_expr(expr_id));
- }
- None => {}
- }
- let expr_id = match csearch::maybe_get_item_ast(tcx, enum_def,
- Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
- csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
- hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
- // NOTE this doesn't do the right thing, it compares inlined
- // NodeId's to the original variant_def's NodeId, but they
- // come from different crates, so they will likely never match.
- variant_expr(&variants[..], variant_def.node).map(|e| e.id)
- }
- _ => None
- },
- _ => None
- };
- tcx.extern_const_variants.borrow_mut().insert(variant_def,
- expr_id.unwrap_or(ast::DUMMY_NODE_ID));
- expr_id.map(|id| tcx.map.expect_expr(id))
+ None
}
}
def_id: DefId,
maybe_ref_id: Option<ast::NodeId>)
-> Option<&'tcx Expr> {
- if def_id.is_local() {
- match tcx.map.find(def_id.node) {
+ if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+ match tcx.map.find(node_id) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
hir::ItemConst(_, ref const_expr) => {
}
let mut used_ref_id = false;
let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
- Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
+ Box::new(astencode::decode_inlined_item)) {
csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => match item.node {
hir::ItemConst(_, ref const_expr) => Some(const_expr.id),
_ => None
}
let fn_id = match csearch::maybe_get_item_ast(tcx, def_id,
- box |a, b, c, d| astencode::decode_inlined_item(a, b, c, d)) {
+ box astencode::decode_inlined_item) {
csearch::FoundAst::Found(&InlinedItem::Item(ref item)) => Some(item.id),
csearch::FoundAst::Found(&InlinedItem::ImplItem(_, ref item)) => Some(item.id),
_ => None
pub fn lookup_const_fn_by_id<'tcx>(tcx: &ty::ctxt<'tcx>, def_id: DefId)
-> Option<FnLikeNode<'tcx>>
{
- let fn_id = if !def_id.is_local() {
+ let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+ node_id
+ } else {
if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
fn_id
} else {
return None;
}
- } else {
- def_id.node
};
let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
}
}
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Debug)]
pub enum ConstVal {
Float(f64),
Int(i64),
Bool(bool),
Struct(ast::NodeId),
Tuple(ast::NodeId),
+ Function(DefId),
+}
+
+/// Note that equality for `ConstVal` means that the it is the same
+/// constant, not that the rust values are equal. In particular, `NaN
+/// == NaN` (at least if it's the same NaN; distinct encodings for NaN
+/// are considering unequal).
+impl PartialEq for ConstVal {
+ fn eq(&self, other: &ConstVal) -> bool {
+ match (self, other) {
+ (&Float(a), &Float(b)) => unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)},
+ (&Int(a), &Int(b)) => a == b,
+ (&Uint(a), &Uint(b)) => a == b,
+ (&Str(ref a), &Str(ref b)) => a == b,
+ (&ByteStr(ref a), &ByteStr(ref b)) => a == b,
+ (&Bool(a), &Bool(b)) => a == b,
+ (&Struct(a), &Struct(b)) => a == b,
+ (&Tuple(a), &Tuple(b)) => a == b,
+ (&Function(a), &Function(b)) => a == b,
+ _ => false,
+ }
+ }
}
impl ConstVal {
Bool(_) => "boolean",
Struct(_) => "struct",
Tuple(_) => "tuple",
+ Function(_) => "function definition",
}
}
}
let field_pats = fields.iter().map(|field| codemap::Spanned {
span: codemap::DUMMY_SP,
node: hir::FieldPat {
- ident: field.ident.node,
+ name: field.name.node,
pat: const_expr_to_pat(tcx, &*field.expr, span),
is_shorthand: false,
},
}
pub fn eval_const_expr(tcx: &ty::ctxt, e: &Expr) -> ConstVal {
- match eval_const_expr_partial(tcx, e, ExprTypeChecked) {
+ match eval_const_expr_partial(tcx, e, ExprTypeChecked, None) {
Ok(r) => r,
Err(s) => tcx.sess.span_fatal(s.span, &s.description())
}
}
+pub type FnArgMap<'a> = Option<&'a NodeMap<ConstVal>>;
#[derive(Clone)]
pub struct ConstEvalErr {
ShiftRightWithOverflow,
MissingStructField,
NonConstPath,
+ UnresolvedPath,
ExpectedConstTuple,
ExpectedConstStruct,
TupleIndexOutOfBounds,
ShiftLeftWithOverflow => "attempted left shift with overflow".into_cow(),
ShiftRightWithOverflow => "attempted right shift with overflow".into_cow(),
MissingStructField => "nonexistent struct field".into_cow(),
- NonConstPath => "non-constant path in constant expr".into_cow(),
+ NonConstPath => "non-constant path in constant expression".into_cow(),
+ UnresolvedPath => "unresolved path in constant expression".into_cow(),
ExpectedConstTuple => "expected constant tuple".into_cow(),
ExpectedConstStruct => "expected constant struct".into_cow(),
TupleIndexOutOfBounds => "tuple index out of bounds".into_cow(),
pub enum UintTy { U8, U16, U32, U64 }
impl IntTy {
- pub fn from(tcx: &ty::ctxt, t: hir::IntTy) -> IntTy {
- let t = if let hir::TyIs = t {
+ pub fn from(tcx: &ty::ctxt, t: ast::IntTy) -> IntTy {
+ let t = if let ast::TyIs = t {
tcx.sess.target.int_type
} else {
t
};
match t {
- hir::TyIs => unreachable!(),
- hir::TyI8 => IntTy::I8,
- hir::TyI16 => IntTy::I16,
- hir::TyI32 => IntTy::I32,
- hir::TyI64 => IntTy::I64,
+ ast::TyIs => unreachable!(),
+ ast::TyI8 => IntTy::I8,
+ ast::TyI16 => IntTy::I16,
+ ast::TyI32 => IntTy::I32,
+ ast::TyI64 => IntTy::I64,
}
}
}
impl UintTy {
- pub fn from(tcx: &ty::ctxt, t: hir::UintTy) -> UintTy {
- let t = if let hir::TyUs = t {
+ pub fn from(tcx: &ty::ctxt, t: ast::UintTy) -> UintTy {
+ let t = if let ast::TyUs = t {
tcx.sess.target.uint_type
} else {
t
};
match t {
- hir::TyUs => unreachable!(),
- hir::TyU8 => UintTy::U8,
- hir::TyU16 => UintTy::U16,
- hir::TyU32 => UintTy::U32,
- hir::TyU64 => UintTy::U64,
+ ast::TyUs => unreachable!(),
+ ast::TyU8 => UintTy::U8,
+ ast::TyU16 => UintTy::U16,
+ ast::TyU32 => UintTy::U32,
+ ast::TyU64 => UintTy::U64,
}
}
}
/// computing the length of an array. (See also the FIXME above EvalHint.)
pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
e: &Expr,
- ty_hint: EvalHint<'tcx>) -> EvalResult {
+ ty_hint: EvalHint<'tcx>,
+ fn_args: FnArgMap) -> EvalResult {
fn fromb(b: bool) -> ConstVal { Int(b as i64) }
// Try to compute the type of the expression based on the EvalHint.
let result = match e.node {
hir::ExprUnary(hir::UnNeg, ref inner) => {
- match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
+ match try!(eval_const_expr_partial(tcx, &**inner, ty_hint, fn_args)) {
Float(f) => Float(-f),
Int(n) => try!(const_int_checked_neg(n, e, expr_int_type)),
Uint(i) => {
}
}
hir::ExprUnary(hir::UnNot, ref inner) => {
- match try!(eval_const_expr_partial(tcx, &**inner, ty_hint)) {
+ match try!(eval_const_expr_partial(tcx, &**inner, ty_hint, fn_args)) {
Int(i) => Int(!i),
Uint(i) => const_uint_not(i, expr_uint_type),
Bool(b) => Bool(!b),
}
_ => ty_hint
};
- match (try!(eval_const_expr_partial(tcx, &**a, ty_hint)),
- try!(eval_const_expr_partial(tcx, &**b, b_ty))) {
+ match (try!(eval_const_expr_partial(tcx, &**a, ty_hint, fn_args)),
+ try!(eval_const_expr_partial(tcx, &**b, b_ty, fn_args))) {
(Float(a), Float(b)) => {
match op.node {
hir::BiAdd => Float(a + b),
}
};
- let val = try!(eval_const_expr_partial(tcx, &**base, base_hint));
+ let val = try!(eval_const_expr_partial(tcx, &**base, base_hint, fn_args));
match cast_const(tcx, val, ety) {
Ok(val) => val,
Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
}
}
hir::ExprPath(..) => {
- let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
+ let opt_def = if let Some(def) = tcx.def_map.borrow().get(&e.id) {
+ // After type-checking, def_map contains definition of the
+ // item referred to by the path. During type-checking, it
+ // can contain the raw output of path resolution, which
+ // might be a partially resolved path.
+ // FIXME: There's probably a better way to make sure we don't
+ // panic here.
+ if def.depth != 0 {
+ signal!(e, UnresolvedPath);
+ }
+ Some(def.full_def())
+ } else {
+ None
+ };
let (const_expr, const_ty) = match opt_def {
Some(def::DefConst(def_id)) => {
- if def_id.is_local() {
- match tcx.map.find(def_id.node) {
+ if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+ match tcx.map.find(node_id) {
Some(ast_map::NodeItem(it)) => match it.node {
hir::ItemConst(ref ty, ref expr) => {
(Some(&**expr), Some(&**ty))
}
}
Some(def::DefAssociatedConst(def_id)) => {
- if def_id.is_local() {
+ if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
match tcx.impl_or_trait_item(def_id).container() {
- ty::TraitContainer(trait_id) => match tcx.map.find(def_id.node) {
+ ty::TraitContainer(trait_id) => match tcx.map.find(node_id) {
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
hir::ConstTraitItem(ref ty, _) => {
if let ExprTypeChecked = ty_hint {
},
_ => (None, None)
},
- ty::ImplContainer(_) => match tcx.map.find(def_id.node) {
+ ty::ImplContainer(_) => match tcx.map.find(node_id) {
Some(ast_map::NodeImplItem(ii)) => match ii.node {
hir::ConstImplItem(ref ty, ref expr) => {
(Some(&**expr), Some(&**ty))
Some(def::DefStruct(_)) => {
return Ok(ConstVal::Struct(e.id))
}
+ Some(def::DefLocal(_, id)) => {
+ debug!("DefLocal({:?}): {:?}", id, fn_args);
+ if let Some(val) = fn_args.and_then(|args| args.get(&id)) {
+ return Ok(val.clone());
+ } else {
+ (None, None)
+ }
+ },
+ Some(def::DefFn(id, _)) => return Ok(Function(id)),
+ // FIXME: implement const methods?
_ => (None, None)
};
let const_expr = match const_expr {
} else {
ty_hint
};
- try!(eval_const_expr_partial(tcx, const_expr, item_hint))
+ try!(eval_const_expr_partial(tcx, const_expr, item_hint, fn_args))
}
+ hir::ExprCall(ref callee, ref args) => {
+ let sub_ty_hint = if let ExprTypeChecked = ty_hint {
+ ExprTypeChecked
+ } else {
+ UncheckedExprNoHint // we cannot reason about UncheckedExprHint here
+ };
+ let (
+ decl,
+ unsafety,
+ abi,
+ block,
+ constness,
+ ) = match try!(eval_const_expr_partial(tcx, callee, sub_ty_hint, fn_args)) {
+ Function(did) => if did.is_local() {
+ match tcx.map.find(did.index.as_u32()) {
+ Some(ast_map::NodeItem(it)) => match it.node {
+ hir::ItemFn(
+ ref decl,
+ unsafety,
+ constness,
+ abi,
+ _, // ducktype generics? types are funky in const_eval
+ ref block,
+ ) => (decl, unsafety, abi, block, constness),
+ _ => signal!(e, NonConstPath),
+ },
+ _ => signal!(e, NonConstPath),
+ }
+ } else {
+ signal!(e, NonConstPath)
+ },
+ _ => signal!(e, NonConstPath),
+ };
+ if let ExprTypeChecked = ty_hint {
+ // no need to check for constness... either check_const
+ // already forbids this or we const eval over whatever
+ // we want
+ } else {
+ // we don't know much about the function, so we force it to be a const fn
+ // so compilation will fail later in case the const fn's body is not const
+ assert_eq!(constness, hir::Constness::Const)
+ }
+ assert_eq!(decl.inputs.len(), args.len());
+ assert_eq!(unsafety, hir::Unsafety::Normal);
+ assert_eq!(abi, abi::Abi::Rust);
+
+ let mut call_args = NodeMap();
+ for (arg, arg_expr) in decl.inputs.iter().zip(args.iter()) {
+ let arg_val = try!(eval_const_expr_partial(
+ tcx,
+ arg_expr,
+ sub_ty_hint,
+ fn_args
+ ));
+ debug!("const call arg: {:?}", arg);
+ let old = call_args.insert(arg.pat.id, arg_val);
+ assert!(old.is_none());
+ }
+ let result = block.expr.as_ref().unwrap();
+ debug!("const call({:?})", call_args);
+ try!(eval_const_expr_partial(tcx, &**result, ty_hint, Some(&call_args)))
+ },
hir::ExprLit(ref lit) => {
lit_to_const(&**lit, ety)
}
- hir::ExprParen(ref e) => try!(eval_const_expr_partial(tcx, &**e, ty_hint)),
hir::ExprBlock(ref block) => {
match block.expr {
- Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint)),
+ Some(ref expr) => try!(eval_const_expr_partial(tcx, &**expr, ty_hint, fn_args)),
None => Int(0)
}
}
} else {
UncheckedExprNoHint
};
- if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
+ if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint, fn_args) {
if let Tuple(tup_id) = c {
if let hir::ExprTup(ref fields) = tcx.map.expect_expr(tup_id).node {
if index.node < fields.len() {
- return eval_const_expr_partial(tcx, &fields[index.node], base_hint)
+ return eval_const_expr_partial(tcx, &fields[index.node], base_hint, fn_args)
} else {
signal!(e, TupleIndexOutOfBounds);
}
} else {
UncheckedExprNoHint
};
- if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint) {
+ if let Ok(c) = eval_const_expr_partial(tcx, base, base_hint, fn_args) {
if let Struct(struct_id) = c {
if let hir::ExprStruct(_, ref fields, _) = tcx.map.expect_expr(struct_id).node {
// Check that the given field exists and evaluate it
// if the idents are compared run-pass/issue-19244 fails
- if let Some(f) = fields.iter().find(|f| f.ident.node.name
- == field_name.node.name) {
- return eval_const_expr_partial(tcx, &*f.expr, base_hint)
+ if let Some(f) = fields.iter().find(|f| f.name.node
+ == field_name.node) {
+ return eval_const_expr_partial(tcx, &*f.expr, base_hint, fn_args)
} else {
signal!(e, MissingStructField);
}
match selection {
traits::VtableImpl(ref impl_data) => {
match tcx.associated_consts(impl_data.impl_def_id)
- .iter().find(|ic| ic.name == ti.ident.name) {
+ .iter().find(|ic| ic.name == ti.name) {
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
None => match ti.node {
hir::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
// Issue #23890: If isize/usize, then dispatch to appropriate target representation type
match (&ty.sty, tcx.sess.target.int_type, tcx.sess.target.uint_type) {
- (&ty::TyInt(hir::TyIs), hir::TyI32, _) => return convert_val!(i32, Int, i64),
- (&ty::TyInt(hir::TyIs), hir::TyI64, _) => return convert_val!(i64, Int, i64),
- (&ty::TyInt(hir::TyIs), _, _) => panic!("unexpected target.int_type"),
+ (&ty::TyInt(ast::TyIs), ast::TyI32, _) => return convert_val!(i32, Int, i64),
+ (&ty::TyInt(ast::TyIs), ast::TyI64, _) => return convert_val!(i64, Int, i64),
+ (&ty::TyInt(ast::TyIs), _, _) => panic!("unexpected target.int_type"),
- (&ty::TyUint(hir::TyUs), _, hir::TyU32) => return convert_val!(u32, Uint, u64),
- (&ty::TyUint(hir::TyUs), _, hir::TyU64) => return convert_val!(u64, Uint, u64),
- (&ty::TyUint(hir::TyUs), _, _) => panic!("unexpected target.uint_type"),
+ (&ty::TyUint(ast::TyUs), _, ast::TyU32) => return convert_val!(u32, Uint, u64),
+ (&ty::TyUint(ast::TyUs), _, ast::TyU64) => return convert_val!(u64, Uint, u64),
+ (&ty::TyUint(ast::TyUs), _, _) => panic!("unexpected target.uint_type"),
_ => {}
}
match ty.sty {
- ty::TyInt(hir::TyIs) => unreachable!(),
- ty::TyUint(hir::TyUs) => unreachable!(),
+ ty::TyInt(ast::TyIs) => unreachable!(),
+ ty::TyUint(ast::TyUs) => unreachable!(),
- ty::TyInt(hir::TyI8) => convert_val!(i8, Int, i64),
- ty::TyInt(hir::TyI16) => convert_val!(i16, Int, i64),
- ty::TyInt(hir::TyI32) => convert_val!(i32, Int, i64),
- ty::TyInt(hir::TyI64) => convert_val!(i64, Int, i64),
+ ty::TyInt(ast::TyI8) => convert_val!(i8, Int, i64),
+ ty::TyInt(ast::TyI16) => convert_val!(i16, Int, i64),
+ ty::TyInt(ast::TyI32) => convert_val!(i32, Int, i64),
+ ty::TyInt(ast::TyI64) => convert_val!(i64, Int, i64),
- ty::TyUint(hir::TyU8) => convert_val!(u8, Uint, u64),
- ty::TyUint(hir::TyU16) => convert_val!(u16, Uint, u64),
- ty::TyUint(hir::TyU32) => convert_val!(u32, Uint, u64),
- ty::TyUint(hir::TyU64) => convert_val!(u64, Uint, u64),
+ ty::TyUint(ast::TyU8) => convert_val!(u8, Uint, u64),
+ ty::TyUint(ast::TyU16) => convert_val!(u16, Uint, u64),
+ ty::TyUint(ast::TyU32) => convert_val!(u32, Uint, u64),
+ ty::TyUint(ast::TyU64) => convert_val!(u64, Uint, u64),
- ty::TyFloat(hir::TyF32) => convert_val!(f32, Float, f64),
- ty::TyFloat(hir::TyF64) => convert_val!(f64, Float, f64),
+ ty::TyFloat(ast::TyF32) => convert_val!(f32, Float, f64),
+ ty::TyFloat(ast::TyF64) => convert_val!(f64, Float, f64),
_ => Err(ErrKind::CannotCast),
}
}
-fn lit_to_const(lit: &hir::Lit, ty_hint: Option<Ty>) -> ConstVal {
+fn lit_to_const(lit: &ast::Lit, ty_hint: Option<Ty>) -> ConstVal {
match lit.node {
- hir::LitStr(ref s, _) => Str((*s).clone()),
- hir::LitByteStr(ref data) => {
+ ast::LitStr(ref s, _) => Str((*s).clone()),
+ ast::LitByteStr(ref data) => {
ByteStr(data.clone())
}
- hir::LitByte(n) => Uint(n as u64),
- hir::LitChar(n) => Uint(n as u64),
- hir::LitInt(n, hir::SignedIntLit(_, hir::Plus)) => Int(n as i64),
- hir::LitInt(n, hir::UnsuffixedIntLit(hir::Plus)) => {
+ ast::LitByte(n) => Uint(n as u64),
+ ast::LitChar(n) => Uint(n as u64),
+ ast::LitInt(n, ast::SignedIntLit(_, ast::Plus)) => Int(n as i64),
+ ast::LitInt(n, ast::UnsuffixedIntLit(ast::Plus)) => {
match ty_hint.map(|ty| &ty.sty) {
Some(&ty::TyUint(_)) => Uint(n),
_ => Int(n as i64)
}
}
- hir::LitInt(n, hir::SignedIntLit(_, hir::Minus)) |
- hir::LitInt(n, hir::UnsuffixedIntLit(hir::Minus)) => Int(-(n as i64)),
- hir::LitInt(n, hir::UnsignedIntLit(_)) => Uint(n),
- hir::LitFloat(ref n, _) |
- hir::LitFloatUnsuffixed(ref n) => {
+ ast::LitInt(n, ast::SignedIntLit(_, ast::Minus)) |
+ ast::LitInt(n, ast::UnsuffixedIntLit(ast::Minus)) => Int(-(n as i64)),
+ ast::LitInt(n, ast::UnsignedIntLit(_)) => Uint(n),
+ ast::LitFloat(ref n, _) |
+ ast::LitFloatUnsuffixed(ref n) => {
Float(n.parse::<f64>().unwrap() as f64)
}
- hir::LitBool(b) => Bool(b)
+ ast::LitBool(b) => Bool(b)
}
}
pub fn compare_lit_exprs<'tcx>(tcx: &ty::ctxt<'tcx>,
a: &Expr,
b: &Expr) -> Option<Ordering> {
- let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked) {
+ let a = match eval_const_expr_partial(tcx, a, ExprTypeChecked, None) {
Ok(a) => a,
Err(e) => {
tcx.sess.span_err(a.span, &e.description());
return None;
}
};
- let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked) {
+ let b = match eval_const_expr_partial(tcx, b, ExprTypeChecked, None) {
Ok(b) => b,
Err(e) => {
tcx.sess.span_err(b.span, &e.description());
use syntax::ast;
use syntax::ast_util::IdRange;
use syntax::print::pp;
+use syntax::print::pprust::PrintState;
use util::nodemap::NodeMap;
use rustc_front::hir;
use rustc_front::visit;
ps: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> {
let id = match node {
- pprust::NodeIdent(_) | pprust::NodeName(_) => 0,
+ pprust::NodeName(_) => 0,
pprust::NodeExpr(expr) => expr.id,
pprust::NodeBlock(blk) => blk.id,
pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0,
use front::map as ast_map;
use rustc_front::hir;
use rustc_front::visit::{self, Visitor};
-use rustc_front::attr::{self, AttrMetaMethods};
use middle::{def, pat_util, privacy, ty};
use middle::def_id::{DefId};
use std::collections::HashSet;
use syntax::{ast, codemap};
+use syntax::attr::{self, AttrMetaMethods};
// Any local node that may call something in its body block should be
// explored. For example, if it's a live NodeItem that is a
// function, then we should explore its block to check for codes that
// may need to be marked as live.
-fn should_explore(tcx: &ty::ctxt, def_id: DefId) -> bool {
- if !def_id.is_local() {
- return false;
- }
-
- match tcx.map.find(def_id.node) {
- Some(ast_map::NodeItem(..))
- | Some(ast_map::NodeImplItem(..))
- | Some(ast_map::NodeForeignItem(..))
- | Some(ast_map::NodeTraitItem(..)) => true,
- _ => false
+fn should_explore(tcx: &ty::ctxt, node_id: ast::NodeId) -> bool {
+ match tcx.map.find(node_id) {
+ Some(ast_map::NodeItem(..)) |
+ Some(ast_map::NodeImplItem(..)) |
+ Some(ast_map::NodeForeignItem(..)) |
+ Some(ast_map::NodeTraitItem(..)) =>
+ true,
+ _ =>
+ false
}
}
struct_has_extern_repr: bool,
ignore_non_const_paths: bool,
inherited_pub_visibility: bool,
- ignore_variant_stack: Vec<ast::NodeId>,
+ ignore_variant_stack: Vec<DefId>,
}
impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
}
fn check_def_id(&mut self, def_id: DefId) {
- if should_explore(self.tcx, def_id) {
- self.worklist.push(def_id.node);
+ if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+ if should_explore(self.tcx, node_id) {
+ self.worklist.push(node_id);
+ }
+ self.live_symbols.insert(node_id);
+ }
+ }
+
+ fn insert_def_id(&mut self, def_id: DefId) {
+ if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+ debug_assert!(!should_explore(self.tcx, node_id));
+ self.live_symbols.insert(node_id);
}
- self.live_symbols.insert(def_id.node);
}
fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
self.tcx.def_map.borrow().get(id).map(|def| {
match def.full_def() {
def::DefConst(_) | def::DefAssociatedConst(..) => {
- self.check_def_id(def.def_id())
+ self.check_def_id(def.def_id());
}
_ if self.ignore_non_const_paths => (),
def::DefPrimTy(_) => (),
+ def::DefSelfTy(..) => (),
def::DefVariant(enum_id, variant_id, _) => {
self.check_def_id(enum_id);
- if !self.ignore_variant_stack.contains(&variant_id.node) {
+ if !self.ignore_variant_stack.contains(&variant_id) {
self.check_def_id(variant_id);
}
}
fn handle_field_access(&mut self, lhs: &hir::Expr, name: ast::Name) {
if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty {
- self.live_symbols.insert(def.struct_variant().field_named(name).did.node);
+ self.insert_def_id(def.struct_variant().field_named(name).did);
} else {
self.tcx.sess.span_bug(lhs.span, "named field access on non-struct")
}
fn handle_tup_field_access(&mut self, lhs: &hir::Expr, idx: usize) {
if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(lhs).sty {
- self.live_symbols.insert(def.struct_variant().fields[idx].did.node);
+ self.insert_def_id(def.struct_variant().fields[idx].did);
}
}
if let hir::PatWild(hir::PatWildSingle) = pat.node.pat.node {
continue;
}
- self.live_symbols.insert(variant.field_named(pat.node.ident.name).did.node);
+ self.insert_def_id(variant.field_named(pat.node.name).did);
}
}
impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> {
- fn visit_struct_def(&mut self, def: &hir::StructDef, _: ast::Ident,
- _: &hir::Generics, _: ast::NodeId) {
+ fn visit_variant_data(&mut self, def: &hir::VariantData, _: ast::Name,
+ _: &hir::Generics, _: ast::NodeId, _: codemap::Span) {
let has_extern_repr = self.struct_has_extern_repr;
let inherited_pub_visibility = self.inherited_pub_visibility;
- let live_fields = def.fields.iter().filter(|f| {
+ let live_fields = def.fields().iter().filter(|f| {
has_extern_repr || inherited_pub_visibility || match f.node.kind {
hir::NamedField(_, hir::Public) => true,
_ => false
hir::ExprMethodCall(..) => {
self.lookup_and_handle_method(expr.id);
}
- hir::ExprField(ref lhs, ref ident) => {
- self.handle_field_access(&**lhs, ident.node.name);
+ hir::ExprField(ref lhs, ref name) => {
+ self.handle_field_access(&**lhs, name.node);
}
hir::ExprTupField(ref lhs, idx) => {
self.handle_tup_field_access(&**lhs, idx.node);
visit::walk_path(self, path);
}
+ fn visit_path_list_item(&mut self, path: &hir::Path, item: &hir::PathListItem) {
+ self.lookup_and_handle_definition(&item.node.id());
+ visit::walk_path_list_item(self, path, item);
+ }
+
fn visit_item(&mut self, _: &hir::Item) {
// Do not recurse into items. These items will be added to the
// worklist and recursed into manually if necessary.
}
}
-fn has_allow_dead_code_or_lang_attr(attrs: &[hir::Attribute]) -> bool {
+fn has_allow_dead_code_or_lang_attr(attrs: &[ast::Attribute]) -> bool {
if attr::contains_name(attrs, "lang") {
return true;
}
let dead_code = lint::builtin::DEAD_CODE.name_lower();
- for attr in lint::gather_attrs_from_hir(attrs) {
+ for attr in lint::gather_attrs(attrs) {
match attr {
Ok((ref name, lint::Allow, _))
if &name[..] == dead_code => return true,
}
match item.node {
hir::ItemEnum(ref enum_def, _) if allow_dead_code => {
- self.worklist.extend(enum_def.variants.iter().map(|variant| variant.node.id));
+ self.worklist.extend(enum_def.variants.iter()
+ .map(|variant| variant.node.data.id()));
}
hir::ItemTrait(_, _, _, ref trait_items) => {
for trait_item in trait_items {
fn get_struct_ctor_id(item: &hir::Item) -> Option<ast::NodeId> {
match item.node {
- hir::ItemStruct(ref struct_def, _) => struct_def.ctor_id,
+ hir::ItemStruct(ref struct_def, _) if !struct_def.is_struct() => {
+ Some(struct_def.id())
+ }
_ => None
}
}
}
fn should_warn_about_field(&mut self, node: &hir::StructField_) -> bool {
- let is_named = node.ident().is_some();
+ let is_named = node.name().is_some();
let field_type = self.tcx.node_id_to_type(node.id);
let is_marker_field = match field_type.ty_to_def_id() {
Some(def_id) => self.tcx.lang_items.items().any(|(_, item)| *item == Some(def_id)),
}
fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool {
- !self.symbol_is_live(variant.id, None)
+ !self.symbol_is_live(variant.data.id(), None)
&& !has_allow_dead_code_or_lang_attr(&variant.attrs)
}
// `ctor_id`. On the other hand, in a statement like
// `type <ident> <generics> = <ty>;` where <ty> refers to a struct_ctor,
// DefMap maps <ty> to `id` instead.
- fn symbol_is_live(&mut self, id: ast::NodeId,
- ctor_id: Option<ast::NodeId>) -> bool {
+ fn symbol_is_live(&mut self,
+ id: ast::NodeId,
+ ctor_id: Option<ast::NodeId>)
+ -> bool {
if self.live_symbols.contains(&id)
|| ctor_id.map_or(false,
|ctor| self.live_symbols.contains(&ctor)) {
// method of a private type is used, but the type itself is never
// called directly.
let impl_items = self.tcx.impl_items.borrow();
- match self.tcx.inherent_impls.borrow().get(&DefId::local(id)) {
+ match self.tcx.inherent_impls.borrow().get(&self.tcx.map.local_def_id(id)) {
None => (),
Some(impl_list) => {
for impl_did in impl_list.iter() {
for item_did in impl_items.get(impl_did).unwrap().iter() {
- if self.live_symbols.contains(&item_did.def_id()
- .node) {
- return true;
+ if let Some(item_node_id) =
+ self.tcx.map.as_local_node_id(item_did.def_id()) {
+ if self.live_symbols.contains(&item_node_id) {
+ return true;
+ }
}
}
}
self.warn_dead_code(
item.id,
item.span,
- item.ident.name,
+ item.name,
item.node.descriptive_variant()
);
} else {
hir::ItemEnum(ref enum_def, _) => {
for variant in &enum_def.variants {
if self.should_warn_about_variant(&variant.node) {
- self.warn_dead_code(variant.node.id, variant.span,
- variant.node.name.name, "variant");
+ self.warn_dead_code(variant.node.data.id(), variant.span,
+ variant.node.name, "variant");
}
}
},
fn visit_foreign_item(&mut self, fi: &hir::ForeignItem) {
if !self.symbol_is_live(fi.id, None) {
- self.warn_dead_code(fi.id, fi.span, fi.ident.name, fi.node.descriptive_variant());
+ self.warn_dead_code(fi.id, fi.span, fi.name, fi.node.descriptive_variant());
}
visit::walk_foreign_item(self, fi);
}
fn visit_struct_field(&mut self, field: &hir::StructField) {
if self.should_warn_about_field(&field.node) {
self.warn_dead_code(field.node.id, field.span,
- field.node.ident().unwrap().name, "struct field");
+ field.node.name().unwrap(), "struct field");
}
visit::walk_struct_field(self, field);
hir::ConstImplItem(_, ref expr) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
- impl_item.ident.name, "associated const");
+ impl_item.name, "associated const");
}
visit::walk_expr(self, expr)
}
hir::MethodImplItem(_, ref body) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
- impl_item.ident.name, "method");
+ impl_item.name, "method");
}
visit::walk_block(self, body)
}
pub use self::Def::*;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::privacy::LastPrivate;
use middle::subst::ParamSpace;
use util::nodemap::NodeMap;
DefStatic(DefId, bool /* is_mutbl */),
DefConst(DefId),
DefAssociatedConst(DefId),
- DefLocal(ast::NodeId),
+ DefLocal(DefId, // def id of variable
+ ast::NodeId), // node id of variable
DefVariant(DefId /* enum */, DefId /* variant */, bool /* is_structure */),
DefTy(DefId, bool /* is_enum */),
DefAssociatedTy(DefId /* trait */, DefId),
DefPrimTy(hir::PrimTy),
DefTyParam(ParamSpace, u32, DefId, ast::Name),
DefUse(DefId),
- DefUpvar(ast::NodeId, // id of closed over local
+ DefUpvar(DefId, // def id of closed over local
+ ast::NodeId, // node id of closed over local
usize, // index in the freevars list of the closure
ast::NodeId), // expr node that creates the closure
/// Note that if it's a tuple struct's definition, the node id of the DefId
- /// may either refer to the item definition's id or the StructDef.ctor_id.
+ /// may either refer to the item definition's id or the VariantData.ctor_id.
///
/// The cases that I have encountered so far are (this is not exhaustive):
/// - If it's a ty_path referring to some tuple struct, then DefMap maps
/// it to a def whose id is the item definition's id.
/// - If it's an ExprPath referring to some tuple struct, then DefMap maps
- /// it to a def whose id is the StructDef.ctor_id.
+ /// it to a def whose id is the VariantData.ctor_id.
DefStruct(DefId),
- DefRegion(ast::NodeId),
DefLabel(ast::NodeId),
DefMethod(DefId),
}
}
impl Def {
- pub fn local_node_id(&self) -> ast::NodeId {
- let def_id = self.def_id();
- assert_eq!(def_id.krate, LOCAL_CRATE);
- def_id.node
+ pub fn var_id(&self) -> ast::NodeId {
+ match *self {
+ DefLocal(_, id) |
+ DefUpvar(_, id, _, _) => {
+ id
+ }
+
+ DefFn(..) | DefMod(..) | DefForeignMod(..) | DefStatic(..) |
+ DefVariant(..) | DefTy(..) | DefAssociatedTy(..) |
+ DefTyParam(..) | DefUse(..) | DefStruct(..) | DefTrait(..) |
+ DefMethod(..) | DefConst(..) | DefAssociatedConst(..) |
+ DefPrimTy(..) | DefLabel(..) | DefSelfTy(..) => {
+ panic!("attempted .def_id() on invalid {:?}", self)
+ }
+ }
}
pub fn def_id(&self) -> DefId {
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
DefMethod(id) | DefConst(id) | DefAssociatedConst(id) |
- DefSelfTy(Some(id), None)=> {
+ DefLocal(id, _) | DefUpvar(id, _, _, _) => {
id
}
- DefLocal(id) |
- DefUpvar(id, _, _) |
- DefRegion(id) |
- DefLabel(id) |
- DefSelfTy(_, Some((_, id))) => {
- DefId::local(id)
- }
- DefPrimTy(_) => panic!("attempted .def_id() on DefPrimTy"),
- DefSelfTy(..) => panic!("attempted .def_id() on invalid DefSelfTy"),
+ DefLabel(..) |
+ DefPrimTy(..) |
+ DefSelfTy(..) => {
+ panic!("attempted .def_id() on invalid def: {:?}", self)
+ }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use metadata::cstore::LOCAL_CRATE;
use middle::ty;
-use syntax::ast::{CrateNum, NodeId};
+use syntax::ast::CrateNum;
use std::fmt;
+use std::u32;
+/// A DefIndex is an index into the hir-map for a crate, identifying a
+/// particular definition. It should really be considered an interned
+/// shorthand for a particular DefPath.
+#[derive(Clone, Debug, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
+ RustcDecodable, Hash, Copy)]
+pub struct DefIndex(u32);
+
+impl DefIndex {
+ pub fn new(x: usize) -> DefIndex {
+ assert!(x < (u32::MAX as usize));
+ DefIndex(x as u32)
+ }
+
+ pub fn from_u32(x: u32) -> DefIndex {
+ DefIndex(x)
+ }
+
+ pub fn as_usize(&self) -> usize {
+ self.0 as usize
+ }
+
+ pub fn as_u32(&self) -> u32 {
+ self.0
+ }
+}
+
+/// The crate root is always assigned index 0 by the AST Map code,
+/// thanks to `NodeCollector::new`.
+pub const CRATE_DEF_INDEX: DefIndex = DefIndex(0);
+
+/// A DefId identifies a particular *definition*, by combining a crate
+/// index and a def index.
#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, RustcEncodable,
RustcDecodable, Hash, Copy)]
pub struct DefId {
pub krate: CrateNum,
- pub node: NodeId,
+ pub index: DefIndex,
}
impl fmt::Debug for DefId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- try!(write!(f, "DefId {{ krate: {}, node: {}",
- self.krate, self.node));
+ try!(write!(f, "DefId {{ krate: {:?}, node: {:?}",
+ self.krate, self.index));
// Unfortunately, there seems to be no way to attempt to print
// a path for a def-id, so I'll just make a best effort for now
// and otherwise fallback to just printing the crate/node pair
- try!(ty::tls::with_opt(|opt_tcx| {
- if let Some(tcx) = opt_tcx {
- try!(write!(f, " => {}", tcx.item_path_str(*self)));
- }
- Ok(())
- }));
+ if self.is_local() { // (1)
+ // (1) side-step fact that not all external things have paths at
+ // the moment, such as type parameters
+ try!(ty::tls::with_opt(|opt_tcx| {
+ if let Some(tcx) = opt_tcx {
+ try!(write!(f, " => {}", tcx.item_path_str(*self)));
+ }
+ Ok(())
+ }));
+ }
write!(f, " }}")
}
impl DefId {
- pub fn local(id: NodeId) -> DefId {
- DefId { krate: LOCAL_CRATE, node: id }
- }
-
- /// Read the node id, asserting that this def-id is krate-local.
- pub fn local_id(&self) -> NodeId {
- assert_eq!(self.krate, LOCAL_CRATE);
- self.node
+ pub fn local(index: DefIndex) -> DefId {
+ DefId { krate: LOCAL_CRATE, index: index }
}
pub fn is_local(&self) -> bool {
self.krate == LOCAL_CRATE
}
}
-
-
-/// Item definitions in the currently-compiled crate would have the CrateNum
-/// LOCAL_CRATE in their DefId.
-pub const LOCAL_CRATE: CrateNum = 0;
-
fn visit_block(&mut self, block: &hir::Block) {
let old_unsafe_context = self.unsafe_context;
match block.rules {
- hir::DefaultBlock => {}
hir::UnsafeBlock(source) => {
// By default only the outermost `unsafe` block is
// "used" and so nested unsafe blocks are pointless
self.unsafe_context.push_unsafe_count =
self.unsafe_context.push_unsafe_count.checked_sub(1).unwrap();
}
+ hir::DefaultBlock | hir::PushUnstableBlock | hir:: PopUnstableBlock => {}
}
visit::walk_block(self, block);
}
}
hir::ExprCall(ref base, _) => {
- let base_type = self.tcx.node_id_to_type(base.id);
+ let base_type = self.tcx.expr_ty_adjusted(base);
debug!("effect: call case, base type is {:?}",
base_type);
if type_is_unsafe_function(base_type) {
}
}
hir::ExprUnary(hir::UnDeref, ref base) => {
- let base_type = self.tcx.node_id_to_type(base.id);
+ let base_type = self.tcx.expr_ty_adjusted(base);
debug!("effect: unary case, base type is {:?}",
base_type);
if let ty::TyRawPtr(_) = base_type.sty {
use front::map as ast_map;
use session::{config, Session};
use syntax::ast::NodeId;
-use rustc_front::hir::{Item, ItemFn};
-use rustc_front::attr;
+use syntax::attr;
use syntax::codemap::Span;
use syntax::entry::EntryPointType;
+use rustc_front::hir::{Item, ItemFn};
use rustc_front::visit;
use rustc_front::visit::Visitor;
EntryPointType::Start
} else if attr::contains_name(&item.attrs, "main") {
EntryPointType::MainAttr
- } else if item.ident.name == "main" {
+ } else if item.name.as_str() == "main" {
if depth == 1 {
// This is a top-level function so can be 'main'
EntryPointType::MainNamed
// can just use the tcx as the typer.
//
// FIXME(stage0): the :'t here is probably only important for stage0
-pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d+'t> {
+pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> {
typer: &'t infer::InferCtxt<'a, 'tcx>,
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
delegate: &'d mut Delegate<'tcx>,
}
impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> {
- pub fn new(delegate: &'d mut Delegate<'tcx>,
+ pub fn new(delegate: &'d mut (Delegate<'tcx>),
typer: &'t infer::InferCtxt<'a, 'tcx>)
- -> ExprUseVisitor<'d,'t,'a,'tcx>
+ -> ExprUseVisitor<'d,'t,'a,'tcx> where 'tcx:'a+'d
{
- let result = ExprUseVisitor {
- typer: typer,
- mc: mc::MemCategorizationContext::new(typer),
- delegate: delegate,
- };
-
- result
+ let mc: mc::MemCategorizationContext<'t, 'a, 'tcx> =
+ mc::MemCategorizationContext::new(typer);
+ ExprUseVisitor { typer: typer, mc: mc, delegate: delegate }
}
pub fn walk_fn(&mut self,
let cmt = return_if_err!(self.mc.cat_expr(expr));
self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
- // Note: Unlike consume, we can ignore ExprParen. cat_expr
- // already skips over them, and walk will uncover any
- // attachments or whatever.
self.walk_expr(expr)
}
self.walk_adjustment(expr);
match expr.node {
- hir::ExprParen(ref subexpr) => {
- self.walk_expr(&**subexpr)
- }
-
hir::ExprPath(..) => { }
hir::ExprUnary(hir::UnDeref, ref base) => { // *base
self.consume_expr(&**base);
}
- hir::ExprAssignOp(_, ref lhs, ref rhs) => {
- // This will have to change if/when we support
- // overloaded operators for `+=` and so forth.
- self.mutate_expr(expr, &**lhs, WriteAndRead);
- self.consume_expr(&**rhs);
+ hir::ExprAssignOp(op, ref lhs, ref rhs) => {
+ // NB All our assignment operations take the RHS by value
+ assert!(::rustc_front::util::is_by_value_binop(op.node));
+
+ if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) {
+ self.mutate_expr(expr, &**lhs, WriteAndRead);
+ self.consume_expr(&**rhs);
+ }
}
hir::ExprRepeat(ref base, ref count) => {
self.walk_captures(expr)
}
- hir::ExprBox(ref place, ref base) => {
- match *place {
- Some(ref place) => self.consume_expr(&**place),
- None => {}
- }
+ hir::ExprBox(ref base) => {
self.consume_expr(&**base);
- if place.is_some() {
- self.tcx().sess.span_bug(
- expr.span,
- "box with explicit place remains after expansion");
- }
}
}
}
-> bool
{
fields.iter().any(
- |f| f.ident.node.name == field.name)
+ |f| f.name.node == field.name)
}
}
self.consume_expr(&*arm.body);
}
- /// Walks an pat that occurs in isolation (i.e. top-level of fn
+ /// Walks a pat that occurs in isolation (i.e. top-level of fn
/// arg or let binding. *Not* a match arm or nested pat.)
fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) {
let mut mode = Unknown;
}
hir::PatIdent(_, _, Some(_)) => {
- // Do nothing; this is a binding (not a enum
+ // Do nothing; this is a binding (not an enum
// variant or struct), and the cat_pattern call
// will visit the substructure recursively.
}
hir::PatRegion(..) | hir::PatLit(..) | hir::PatRange(..) |
hir::PatVec(..) => {
// Similarly, each of these cases does not
- // correspond to a enum variant or struct, so we
+ // correspond to an enum variant or struct, so we
// do not do any `matched_pat` calls for these
// cases either.
}
self.tcx().with_freevars(closure_expr.id, |freevars| {
for freevar in freevars {
- let id_var = freevar.def.def_id().node;
+ let id_var = freevar.def.var_id();
let upvar_id = ty::UpvarId { var_id: id_var,
closure_expr_id: closure_expr.id };
let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap();
-> mc::McResult<mc::cmt<'tcx>> {
// Create the cmt for the variable being borrowed, from the
// caller's perspective
- let var_id = upvar_def.def_id().node;
+ let var_id = upvar_def.var_id();
let var_ty = try!(self.typer.node_ty(var_id));
self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
}
//! This file handles the relationships between free regions --
//! meaning lifetime parameters. Ordinarily, free regions are
-//! unrelated to one another, but they can be related vai implied or
+//! unrelated to one another, but they can be related via implied or
//! explicit bounds. In that case, we track the bounds using the
//! `TransitiveRelation` type and use that to decide when one free
//! region outlives another and so forth.
use middle::ty::fold::{TypeFolder, TypeFoldable};
use middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use syntax::ast;
use syntax::codemap::Span;
-use rustc_front::hir;
#[derive(Clone)]
pub struct CombineFields<'a, 'tcx: 'a> {
fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
vid_is_expected: bool,
vid: ty::FloatVid,
- val: hir::FloatTy)
+ val: ast::FloatTy)
-> RelateResult<'tcx, Ty<'tcx>>
{
try!(infcx
}
fn float_unification_error<'tcx>(a_is_expected: bool,
- v: (hir::FloatTy, hir::FloatTy))
+ v: (ast::FloatTy, ast::FloatTy))
-> TypeError<'tcx>
{
let (a, b) = v;
use middle::ty::TyVar;
use middle::ty::relate::{Relate, RelateResult, TypeRelation};
+/// Ensures `a` is made equal to `b`. Returns `a` on success.
pub struct Equate<'a, 'tcx: 'a> {
fields: CombineFields<'a, 'tcx>
}
}
_ => {
- combine::super_combine_tys(self.fields.infcx, self, a, b)
+ try!(combine::super_combine_tys(self.fields.infcx, self, a, b));
+ Ok(a)
}
}
}
use super::region_inference::RegionResolutionError;
use super::region_inference::ConcreteFailure;
use super::region_inference::SubSupConflict;
-use super::region_inference::SupSupConflict;
use super::region_inference::GenericBoundFailure;
use super::region_inference::GenericKind;
use super::region_inference::ProcessedErrors;
sup_origin: SubregionOrigin<'tcx>,
sup_region: Region);
- fn report_sup_sup_conflict(&self,
- var_origin: RegionVariableOrigin,
- origin1: SubregionOrigin<'tcx>,
- region1: Region,
- origin2: SubregionOrigin<'tcx>,
- region2: Region);
-
fn report_processed_errors(&self,
var_origin: &[RegionVariableOrigin],
trace_origin: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
decl: &hir::FnDecl,
unsafety: hir::Unsafety,
constness: hir::Constness,
- ident: ast::Ident,
+ name: ast::Name,
opt_explicit_self: Option<&hir::ExplicitSelf_>,
generics: &hir::Generics,
span: Span);
sup_origin, sup_r);
}
- SupSupConflict(var_origin,
- origin1, r1,
- origin2, r2) => {
- self.report_sup_sup_conflict(var_origin,
- origin1, r1,
- origin2, r2);
- }
-
ProcessedErrors(ref var_origins,
ref trace_origins,
ref same_regions) => {
None => processed_errors.push((*error).clone()),
}
}
- SupSupConflict(..) => processed_errors.push((*error).clone()),
_ => () // This shouldn't happen
}
}
"");
}
infer::DerefPointer(span) => {
- self.tcx.sess.span_err(
- span,
- "dereference of reference outside its lifetime");
+ span_err!(self.tcx.sess, span, E0473,
+ "dereference of reference outside its lifetime");
self.tcx.note_and_explain_region(
"the reference is only valid for ",
sup,
"");
}
infer::FreeVariable(span, id) => {
- self.tcx.sess.span_err(
- span,
- &format!("captured variable `{}` does not \
- outlive the enclosing closure",
- self.tcx.local_var_name_str(id)));
+ span_err!(self.tcx.sess, span, E0474,
+ "captured variable `{}` does not outlive the enclosing closure",
+ self.tcx.local_var_name_str(id));
self.tcx.note_and_explain_region(
"captured variable is valid for ",
sup,
"");
}
infer::IndexSlice(span) => {
- self.tcx.sess.span_err(span,
- "index of slice outside its lifetime");
+ span_err!(self.tcx.sess, span, E0475,
+ "index of slice outside its lifetime");
self.tcx.note_and_explain_region(
"the slice is only valid for ",
sup,
"");
}
infer::RelateObjectBound(span) => {
- self.tcx.sess.span_err(
- span,
- "lifetime of the source pointer does not outlive \
- lifetime bound of the object type");
+ span_err!(self.tcx.sess, span, E0476,
+ "lifetime of the source pointer does not outlive \
+ lifetime bound of the object type");
self.tcx.note_and_explain_region(
"object type is valid for ",
sub,
"");
}
infer::RelateParamBound(span, ty) => {
- self.tcx.sess.span_err(
- span,
- &format!("the type `{}` does not fulfill the \
- required lifetime",
- self.ty_to_string(ty)));
+ span_err!(self.tcx.sess, span, E0477,
+ "the type `{}` does not fulfill the required lifetime",
+ self.ty_to_string(ty));
self.tcx.note_and_explain_region(
"type must outlive ",
sub,
"");
}
infer::RelateRegionParamBound(span) => {
- self.tcx.sess.span_err(
- span,
- "lifetime bound not satisfied");
+ span_err!(self.tcx.sess, span, E0478,
+ "lifetime bound not satisfied");
self.tcx.note_and_explain_region(
"lifetime parameter instantiated with ",
sup,
"");
}
infer::RelateDefaultParamBound(span, ty) => {
- self.tcx.sess.span_err(
- span,
- &format!("the type `{}` (provided as the value of \
- a type parameter) is not valid at this point",
- self.ty_to_string(ty)));
+ span_err!(self.tcx.sess, span, E0479,
+ "the type `{}` (provided as the value of \
+ a type parameter) is not valid at this point",
+ self.ty_to_string(ty));
self.tcx.note_and_explain_region(
"type must outlive ",
sub,
"");
}
infer::CallRcvr(span) => {
- self.tcx.sess.span_err(
- span,
- "lifetime of method receiver does not outlive \
- the method call");
+ span_err!(self.tcx.sess, span, E0480,
+ "lifetime of method receiver does not outlive \
+ the method call");
self.tcx.note_and_explain_region(
"the receiver is only valid for ",
sup,
"");
}
infer::CallArg(span) => {
- self.tcx.sess.span_err(
- span,
- "lifetime of function argument does not outlive \
- the function call");
+ span_err!(self.tcx.sess, span, E0481,
+ "lifetime of function argument does not outlive \
+ the function call");
self.tcx.note_and_explain_region(
"the function argument is only valid for ",
sup,
"");
}
infer::CallReturn(span) => {
- self.tcx.sess.span_err(
- span,
- "lifetime of return value does not outlive \
- the function call");
+ span_err!(self.tcx.sess, span, E0482,
+ "lifetime of return value does not outlive \
+ the function call");
self.tcx.note_and_explain_region(
"the return value is only valid for ",
sup,
"");
}
infer::Operand(span) => {
- self.tcx.sess.span_err(
- span,
- "lifetime of operand does not outlive \
- the operation");
+ span_err!(self.tcx.sess, span, E0483,
+ "lifetime of operand does not outlive \
+ the operation");
self.tcx.note_and_explain_region(
"the operand is only valid for ",
sup,
"");
}
infer::AddrOf(span) => {
- self.tcx.sess.span_err(
- span,
- "reference is not valid \
- at the time of borrow");
+ span_err!(self.tcx.sess, span, E0484,
+ "reference is not valid at the time of borrow");
self.tcx.note_and_explain_region(
"the borrow is only valid for ",
sup,
"");
}
infer::AutoBorrow(span) => {
- self.tcx.sess.span_err(
- span,
- "automatically reference is not valid \
- at the time of borrow");
+ span_err!(self.tcx.sess, span, E0485,
+ "automatically reference is not valid \
+ at the time of borrow");
self.tcx.note_and_explain_region(
"the automatic borrow is only valid for ",
sup,
"");
}
infer::ExprTypeIsNotInScope(t, span) => {
- self.tcx.sess.span_err(
- span,
- &format!("type of expression contains references \
- that are not valid during the expression: `{}`",
- self.ty_to_string(t)));
+ span_err!(self.tcx.sess, span, E0486,
+ "type of expression contains references \
+ that are not valid during the expression: `{}`",
+ self.ty_to_string(t));
self.tcx.note_and_explain_region(
"type is only valid for ",
sup,
"");
}
infer::SafeDestructor(span) => {
- self.tcx.sess.span_err(
- span,
- "unsafe use of destructor: destructor might be called \
- while references are dead");
+ span_err!(self.tcx.sess, span, E0487,
+ "unsafe use of destructor: destructor might be called \
+ while references are dead");
// FIXME (22171): terms "super/subregion" are suboptimal
self.tcx.note_and_explain_region(
"superregion: ",
"");
}
infer::BindingTypeIsNotValidAtDecl(span) => {
- self.tcx.sess.span_err(
- span,
- "lifetime of variable does not enclose its declaration");
+ span_err!(self.tcx.sess, span, E0488,
+ "lifetime of variable does not enclose its declaration");
self.tcx.note_and_explain_region(
"the variable is only valid for ",
sup,
"");
}
infer::ParameterInScope(_, span) => {
- self.tcx.sess.span_err(
- span,
- &format!("type/lifetime parameter not in scope here"));
+ span_err!(self.tcx.sess, span, E0489,
+ "type/lifetime parameter not in scope here");
self.tcx.note_and_explain_region(
"the parameter is only valid for ",
sub,
"");
}
infer::DataBorrowed(ty, span) => {
- self.tcx.sess.span_err(
- span,
- &format!("a value of type `{}` is borrowed for too long",
- self.ty_to_string(ty)));
+ span_err!(self.tcx.sess, span, E0490,
+ "a value of type `{}` is borrowed for too long",
+ self.ty_to_string(ty));
self.tcx.note_and_explain_region("the type is valid for ", sub, "");
self.tcx.note_and_explain_region("but the borrow lasts for ", sup, "");
}
infer::ReferenceOutlivesReferent(ty, span) => {
- self.tcx.sess.span_err(
- span,
- &format!("in type `{}`, reference has a longer lifetime \
- than the data it references",
- self.ty_to_string(ty)));
+ span_err!(self.tcx.sess, span, E0491,
+ "in type `{}`, reference has a longer lifetime \
+ than the data it references",
+ self.ty_to_string(ty));
self.tcx.note_and_explain_region(
"the pointer is valid for ",
sub,
self.note_region_origin(&sub_origin);
}
- fn report_sup_sup_conflict(&self,
- var_origin: RegionVariableOrigin,
- origin1: SubregionOrigin<'tcx>,
- region1: Region,
- origin2: SubregionOrigin<'tcx>,
- region2: Region) {
- self.report_inference_failure(var_origin);
-
- self.tcx.note_and_explain_region(
- "first, the lifetime must be contained by ",
- region1,
- "...");
-
- self.note_region_origin(&origin1);
-
- self.tcx.note_and_explain_region(
- "but, the lifetime must also be contained by ",
- region2,
- "...");
-
- self.note_region_origin(&origin2);
- }
-
fn report_processed_errors(&self,
var_origins: &[RegionVariableOrigin],
trace_origins: &[(TypeTrace<'tcx>, TypeError<'tcx>)],
match item.node {
hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
Some((fn_decl, gen, unsafety, constness,
- item.ident, None, item.span))
+ item.name, None, item.span))
},
_ => None
}
&sig.generics,
sig.unsafety,
sig.constness,
- item.ident,
+ item.name,
Some(&sig.explicit_self.node),
item.span))
}
&sig.generics,
sig.unsafety,
sig.constness,
- item.ident,
+ item.name,
Some(&sig.explicit_self.node),
item.span))
}
},
None => None
};
- let (fn_decl, generics, unsafety, constness, ident, expl_self, span)
+ let (fn_decl, generics, unsafety, constness, name, expl_self, span)
= node_inner.expect("expect item fn");
let rebuilder = Rebuilder::new(self.tcx, fn_decl, expl_self,
generics, same_regions, &life_giver);
let (fn_decl, expl_self, generics) = rebuilder.rebuild();
- self.give_expl_lifetime_param(&fn_decl, unsafety, constness, ident,
+ self.give_expl_lifetime_param(&fn_decl, unsafety, constness, name,
expl_self.as_ref(), &generics, span);
}
}
names.push(lt_name);
}
names.sort();
- let name = token::str_to_ident(&names[0]).name;
+ let name = token::intern(&names[0]);
return (name_to_dummy_lifetime(name), Kept);
}
return (self.life_giver.give_lifetime(), Fresh);
lifetime,
region_names);
hir::TyParam {
- ident: ty_param.ident,
+ name: ty_param.name,
id: ty_param.id,
bounds: bounds,
default: ty_param.default.clone(),
let new_bindings = data.bindings.map(|b| {
P(hir::TypeBinding {
id: b.id,
- ident: b.ident,
+ name: b.name,
ty: self.rebuild_arg_ty_or_output(&*b.ty,
lifetime,
anon_nums,
decl: &hir::FnDecl,
unsafety: hir::Unsafety,
constness: hir::Constness,
- ident: ast::Ident,
+ name: ast::Name,
opt_explicit_self: Option<&hir::ExplicitSelf_>,
generics: &hir::Generics,
span: Span) {
- let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, ident,
+ let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name,
opt_explicit_self, generics);
let msg = format!("consider using an explicit lifetime \
parameter as shown: {}", suggested_fn);
}
};
- self.tcx.sess.span_err(
- var_origin.span(),
- &format!("cannot infer an appropriate lifetime{} \
- due to conflicting requirements",
- var_description));
+ span_err!(self.tcx.sess, var_origin.span(), E0495,
+ "cannot infer an appropriate lifetime{} \
+ due to conflicting requirements",
+ var_description);
}
fn note_region_origin(&self, origin: &SubregionOrigin<'tcx>) {
"...so that return value is valid for the call");
}
infer::Operand(span) => {
- self.tcx.sess.span_err(
+ self.tcx.sess.span_note(
span,
"...so that operand is valid for operation");
}
let mut s = String::from("'");
s.push_str(&num_to_string(self.counter.get()));
if !self.taken.contains(&s) {
- lifetime = name_to_dummy_lifetime(
- token::str_to_ident(&s[..]).name);
+ lifetime = name_to_dummy_lifetime(token::intern(&s[..]));
self.generated.borrow_mut().push(lifetime);
break;
}
// Compute a mapping from the "taint set" of each skolemized
// region back to the `ty::BoundRegion` that it originally
- // represented. Because `leak_check` passed, we know that that
+ // represented. Because `leak_check` passed, we know that
// these taint sets are mutually disjoint.
let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
skol_map
def_id: DefId)
-> Option<ty::ClosureKind>
{
- self.tables.borrow().closure_kinds.get(&def_id).cloned()
+ if def_id.is_local() {
+ self.tables.borrow().closure_kinds.get(&def_id).cloned()
+ } else {
+ // During typeck, ALL closures are local. But afterwards,
+ // during trans, we see closure ids from other traits.
+ // That may require loading the closure data out of the
+ // cstore.
+ Some(ty::Tables::closure_kind(&self.tables, self.tcx, def_id))
+ }
}
pub fn closure_type(&self,
substs: &ty::ClosureSubsts<'tcx>)
-> ty::ClosureTy<'tcx>
{
- let closure_ty = self.tables
- .borrow()
- .closure_tys
- .get(&def_id)
- .unwrap()
- .subst(self.tcx, &substs.func_substs);
+ let closure_ty =
+ ty::Tables::closure_type(self.tables,
+ self.tcx,
+ def_id,
+ substs);
if self.normalize {
normalize_associated_type(&self.tcx, &closure_ty)
# Terminology
-Note that we use the terms region and lifetime interchangeably,
-though the term `lifetime` is preferred.
+Note that we use the terms region and lifetime interchangeably.
# Introduction
Region inference uses a somewhat more involved algorithm than type
-inference. It is not the most efficient thing ever written though it
+inference. It is not the most efficient thing ever written though it
seems to work well enough in practice (famous last words). The reason
that we use a different algorithm is because, unlike with types, it is
impractical to hand-annotate with regions (in some cases, there aren't
The constraints are always of one of three possible forms:
-- ConstrainVarSubVar(R_i, R_j) states that region variable R_i
- must be a subregion of R_j
-- ConstrainRegSubVar(R, R_i) states that the concrete region R
- (which must not be a variable) must be a subregion of the variable R_i
-- ConstrainVarSubReg(R_i, R) is the inverse
+- `ConstrainVarSubVar(Ri, Rj)` states that region variable Ri must be
+ a subregion of Rj
+- `ConstrainRegSubVar(R, Ri)` states that the concrete region R (which
+ must not be a variable) must be a subregion of the variable Ri
+- `ConstrainVarSubReg(Ri, R)` states the variable Ri shoudl be less
+ than the concrete region R. This is kind of deprecated and ought to
+ be replaced with a verify (they essentially play the same role).
+
+In addition to constraints, we also gather up a set of "verifys"
+(what, you don't think Verify is a noun? Get used to it my
+friend!). These represent relations that must hold but which don't
+influence inference proper. These take the form of:
+
+- `VerifyRegSubReg(Ri, Rj)` indicates that Ri <= Rj must hold,
+ where Rj is not an inference variable (and Ri may or may not contain
+ one). This doesn't influence inference because we will already have
+ inferred Ri to be as small as possible, so then we just test whether
+ that result was less than Rj or not.
+- `VerifyGenericBound(R, Vb)` is a more complex expression which tests
+ that the region R must satisfy the bound `Vb`. The bounds themselves
+ may have structure like "must outlive one of the following regions"
+ or "must outlive ALL of the following regions. These bounds arise
+ from constraints like `T: 'a` -- if we know that `T: 'b` and `T: 'c`
+ (say, from where clauses), then we can conclude that `T: 'a` if `'b:
+ 'a` *or* `'c: 'a`.
# Building up the constraints
Variables and constraints are created using the following methods:
- `new_region_var()` creates a new, unconstrained region variable;
-- `make_subregion(R_i, R_j)` states that R_i is a subregion of R_j
-- `lub_regions(R_i, R_j) -> R_k` returns a region R_k which is
- the smallest region that is greater than both R_i and R_j
-- `glb_regions(R_i, R_j) -> R_k` returns a region R_k which is
- the greatest region that is smaller than both R_i and R_j
+- `make_subregion(Ri, Rj)` states that Ri is a subregion of Rj
+- `lub_regions(Ri, Rj) -> Rk` returns a region Rk which is
+ the smallest region that is greater than both Ri and Rj
+- `glb_regions(Ri, Rj) -> Rk` returns a region Rk which is
+ the greatest region that is smaller than both Ri and Rj
The actual region resolution algorithm is not entirely
obvious, though it is also not overly complex.
Snapshots can be recursive---so you can start a snapshot when another
is in progress, but only the root snapshot can "commit".
-# Resolving constraints
-
-The constraint resolution algorithm is not super complex but also not
-entirely obvious. Here I describe the problem somewhat abstractly,
-then describe how the current code works. There may be other, smarter
-ways of doing this with which I am unfamiliar and can't be bothered to
-research at the moment. - NDM
-
## The problem
Basically our input is a directed graph where nodes can be divided
that maps `Constraint` keys to spans. During resolution, we construct
the actual `Graph` structure that we describe here.
-## Our current algorithm
-
-We divide region variables into two groups: Expanding and Contracting.
-Expanding region variables are those that have a concrete region
-predecessor (direct or indirect). Contracting region variables are
-all others.
-
-We first resolve the values of Expanding region variables and then
-process Contracting ones. We currently use an iterative, fixed-point
-procedure (but read on, I believe this could be replaced with a linear
-walk). Basically we iterate over the edges in the graph, ensuring
-that, if the source of the edge has a value, then this value is a
-subregion of the target value. If the target does not yet have a
-value, it takes the value from the source. If the target already had
-a value, then the resulting value is Least Upper Bound of the old and
-new values. When we are done, each Expanding node will have the
-smallest region that it could possibly have and still satisfy the
-constraints.
-
-We next process the Contracting nodes. Here we again iterate over the
-edges, only this time we move values from target to source (if the
-source is a Contracting node). For each contracting node, we compute
-its value as the GLB of all its successors. Basically contracting
-nodes ensure that there is overlap between their successors; we will
-ultimately infer the largest overlap possible.
+## Computing the values for region variables
+
+The algorithm is a simple dataflow algorithm. Each region variable
+begins as empty. We iterate over the constraints, and for each constraint
+we grow the relevant region variable to be as big as it must be to meet all the
+constraints. This means the region variables can grow to be `'static` if
+necessary.
+
+## Verification
+
+After all constraints are fully propoagated, we do a "verification"
+step where we walk over the verify bounds and check that they are
+satisfied. These bounds represent the "maximal" values that a region
+variable can take on, basically.
# The Region Hierarchy
pub use self::CombineMapType::*;
pub use self::RegionResolutionError::*;
pub use self::VarValue::*;
-use self::Classification::*;
use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable};
use rustc_data_structures::graph::{self, Direction, NodeIndex};
use middle::free_region::FreeRegionMap;
-use middle::region;
use middle::ty::{self, Ty};
use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid};
use middle::ty::{ReEmpty, ReStatic, ReFree, ReEarlyBound};
use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh};
use middle::ty::error::TypeError;
-use middle::ty::relate::RelateResult;
use util::common::indenter;
use util::nodemap::{FnvHashMap, FnvHashSet};
ConstrainRegSubVar(Region, RegionVid),
// Region variable is subregion of concrete region
+ //
+ // FIXME(#29436) -- should be remove in favor of a Verify
ConstrainVarSubReg(RegionVid, Region),
}
SubregionOrigin<'tcx>, Region,
SubregionOrigin<'tcx>, Region),
- /// `SupSupConflict(v, origin1, r1, origin2, r2)`:
- ///
- /// Could not infer a value for `v` because `v <= r1` (due to
- /// `origin1`) and `v <= r2` (due to `origin2`) and
- /// `r1` and `r2` have no intersection.
- SupSupConflict(RegionVariableOrigin,
- SubregionOrigin<'tcx>, Region,
- SubregionOrigin<'tcx>, Region),
-
/// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive
/// more specific errors message by suggesting to the user where they
/// should put a lifetime. In those cases we process and put those errors
}
}
}
-
- fn glb_concrete_regions(&self,
- free_regions: &FreeRegionMap,
- a: Region,
- b: Region)
- -> RelateResult<'tcx, Region>
- {
- debug!("glb_concrete_regions({:?}, {:?})", a, b);
- match (a, b) {
- (ReLateBound(..), _) |
- (_, ReLateBound(..)) |
- (ReEarlyBound(..), _) |
- (_, ReEarlyBound(..)) => {
- self.tcx.sess.bug(
- &format!("cannot relate bound region: GLB({:?}, {:?})",
- a,
- b));
- }
-
- (ReStatic, r) | (r, ReStatic) => {
- // static lives longer than everything else
- Ok(r)
- }
-
- (ReEmpty, _) | (_, ReEmpty) => {
- // nothing lives shorter than everything else
- Ok(ReEmpty)
- }
-
- (ReVar(v_id), _) |
- (_, ReVar(v_id)) => {
- self.tcx.sess.span_bug(
- (*self.var_origins.borrow())[v_id.index as usize].span(),
- &format!("glb_concrete_regions invoked with \
- non-concrete regions: {:?}, {:?}",
- a,
- b));
- }
-
- (ReFree(fr), ReScope(s_id)) |
- (ReScope(s_id), ReFree(fr)) => {
- let s = ReScope(s_id);
- // Free region is something "at least as big as
- // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger
- // than the scope `s_id`, then we can say that the GLB
- // is the scope `s_id`. Otherwise, as we do not know
- // big the free region is precisely, the GLB is undefined.
- if self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) == fr.scope ||
- free_regions.is_static(fr) {
- Ok(s)
- } else {
- Err(TypeError::RegionsNoOverlap(b, a))
- }
- }
-
- (ReScope(a_id), ReScope(b_id)) => {
- self.intersect_scopes(a, b, a_id, b_id)
- }
-
- (ReFree(ref a_fr), ReFree(ref b_fr)) => {
- self.glb_free_regions(free_regions, a_fr, b_fr)
- }
-
- // For these types, we cannot define any additional
- // relationship:
- (ReSkolemized(..), _) |
- (_, ReSkolemized(..)) => {
- if a == b {
- Ok(a)
- } else {
- Err(TypeError::RegionsNoOverlap(b, a))
- }
- }
- }
- }
-
- /// Computes a region that is enclosed by both free region arguments, if any. Guarantees that
- /// if the same two regions are given as argument, in any order, a consistent result is
- /// returned.
- fn glb_free_regions(&self,
- free_regions: &FreeRegionMap,
- a: &FreeRegion,
- b: &FreeRegion)
- -> RelateResult<'tcx, ty::Region>
- {
- return match a.cmp(b) {
- Less => helper(self, free_regions, a, b),
- Greater => helper(self, free_regions, b, a),
- Equal => Ok(ty::ReFree(*a))
- };
-
- fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>,
- free_regions: &FreeRegionMap,
- a: &FreeRegion,
- b: &FreeRegion) -> RelateResult<'tcx, ty::Region>
- {
- if free_regions.sub_free_region(*a, *b) {
- Ok(ty::ReFree(*a))
- } else if free_regions.sub_free_region(*b, *a) {
- Ok(ty::ReFree(*b))
- } else {
- this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
- a.scope, b.scope)
- }
- }
- }
-
- fn intersect_scopes(&self,
- region_a: ty::Region,
- region_b: ty::Region,
- scope_a: region::CodeExtent,
- scope_b: region::CodeExtent)
- -> RelateResult<'tcx, Region>
- {
- // We want to generate the intersection of two
- // scopes or two free regions. So, if one of
- // these scopes is a subscope of the other, return
- // it. Otherwise fail.
- debug!("intersect_scopes(scope_a={:?}, scope_b={:?}, region_a={:?}, region_b={:?})",
- scope_a, scope_b, region_a, region_b);
- let r_id = self.tcx.region_maps.nearest_common_ancestor(scope_a, scope_b);
- if r_id == scope_a {
- Ok(ReScope(scope_b))
- } else if r_id == scope_b {
- Ok(ReScope(scope_a))
- } else {
- Err(TypeError::RegionsNoOverlap(region_a, region_b))
- }
- }
}
// ______________________________________________________________________
-#[derive(Copy, Clone, PartialEq, Debug)]
-enum Classification { Expanding, Contracting }
-
#[derive(Copy, Clone, Debug)]
-pub enum VarValue { NoValue, Value(Region), ErrorValue }
+pub enum VarValue { Value(Region), ErrorValue }
struct VarData {
- classification: Classification,
value: VarValue,
}
fn construct_var_data(&self) -> Vec<VarData> {
(0..self.num_vars() as usize).map(|_| {
VarData {
- // All nodes are initially classified as contracting; during
- // the expansion phase, we will shift the classification for
- // those nodes that have a concrete region predecessor to
- // Expanding.
- classification: Contracting,
- value: NoValue,
+ value: Value(ty::ReEmpty),
}
}).collect()
}
}
ConstrainVarSubVar(a_vid, b_vid) => {
match var_data[a_vid.index as usize].value {
- NoValue | ErrorValue => false,
- Value(a_region) => {
- let b_node = &mut var_data[b_vid.index as usize];
- self.expand_node(free_regions, a_region, b_vid, b_node)
- }
+ ErrorValue => false,
+ Value(a_region) => {
+ let b_node = &mut var_data[b_vid.index as usize];
+ self.expand_node(free_regions, a_region, b_vid, b_node)
+ }
}
}
ConstrainVarSubReg(..) => {
_ => { }
}
- b_data.classification = Expanding;
match b_data.value {
- NoValue => {
- debug!("Setting initial value of {:?} to {:?}",
- b_vid, a_region);
-
- b_data.value = Value(a_region);
- return true;
- }
-
Value(cur_region) => {
let lub = self.lub_concrete_regions(free_regions, a_region, cur_region);
if lub == cur_region {
}
}
+ // FIXME(#29436) -- this fn would just go away if we removed ConstrainVarSubReg
fn contraction(&self,
free_regions: &FreeRegionMap,
var_data: &mut [VarData]) {
.unwrap()
);
match *constraint {
- ConstrainRegSubVar(..) => {
- // This is an expansion constraint. Ignore.
- false
- }
- ConstrainVarSubVar(a_vid, b_vid) => {
- match var_data[b_vid.index as usize].value {
- NoValue | ErrorValue => false,
- Value(b_region) => {
- let a_data = &mut var_data[a_vid.index as usize];
- self.contract_node(free_regions, a_vid, a_data, b_region)
- }
+ ConstrainRegSubVar(..) |
+ ConstrainVarSubVar(..) => {
+ // Expansion will ensure that these constraints hold. Ignore.
}
- }
- ConstrainVarSubReg(a_vid, b_region) => {
- let a_data = &mut var_data[a_vid.index as usize];
- self.contract_node(free_regions, a_vid, a_data, b_region)
- }
- }
- })
- }
-
- fn contract_node(&self,
- free_regions: &FreeRegionMap,
- a_vid: RegionVid,
- a_data: &mut VarData,
- b_region: Region)
- -> bool {
- debug!("contract_node({:?} == {:?}/{:?}, {:?})",
- a_vid, a_data.value,
- a_data.classification, b_region);
-
- return match a_data.value {
- NoValue => {
- assert_eq!(a_data.classification, Contracting);
- a_data.value = Value(b_region);
- true // changed
- }
-
- ErrorValue => false, // no change
-
- Value(a_region) => {
- match a_data.classification {
- Expanding =>
- check_node(self, free_regions, a_vid, a_data, a_region, b_region),
- Contracting =>
- adjust_node(self, free_regions, a_vid, a_data, a_region, b_region),
+ ConstrainVarSubReg(a_vid, b_region) => {
+ let a_data = &mut var_data[a_vid.index as usize];
+ debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data.value, b_region);
+
+ let a_region = match a_data.value {
+ ErrorValue => return false,
+ Value(a_region) => a_region,
+ };
+
+ if !free_regions.is_subregion_of(self.tcx, a_region, b_region) {
+ debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
+ a_vid,
+ a_region,
+ b_region);
+ a_data.value = ErrorValue;
+ }
}
}
- };
- fn check_node(this: &RegionVarBindings,
- free_regions: &FreeRegionMap,
- a_vid: RegionVid,
- a_data: &mut VarData,
- a_region: Region,
- b_region: Region)
- -> bool
- {
- if !free_regions.is_subregion_of(this.tcx, a_region, b_region) {
- debug!("Setting {:?} to ErrorValue: {:?} not subregion of {:?}",
- a_vid,
- a_region,
- b_region);
- a_data.value = ErrorValue;
- }
false
- }
-
- fn adjust_node(this: &RegionVarBindings,
- free_regions: &FreeRegionMap,
- a_vid: RegionVid,
- a_data: &mut VarData,
- a_region: Region,
- b_region: Region)
- -> bool {
- match this.glb_concrete_regions(free_regions, a_region, b_region) {
- Ok(glb) => {
- if glb == a_region {
- false
- } else {
- debug!("Contracting value of {:?} from {:?} to {:?}",
- a_vid,
- a_region,
- glb);
- a_data.value = Value(glb);
- true
- }
- }
- Err(_) => {
- debug!("Setting {:?} to ErrorValue: no glb of {:?}, {:?}",
- a_vid,
- a_region,
- b_region);
- a_data.value = ErrorValue;
- false
- }
- }
- }
+ })
}
fn collect_concrete_region_errors(&self,
Value(_) => {
/* Inference successful */
}
- NoValue => {
- /* Unconstrained inference: do not report an error
- until the value of this variable is requested.
- After all, sometimes we make region variables but never
- really use their values. */
- }
ErrorValue => {
/* Inference impossible, this value contains
inconsistent constraints.
this portion of the code and think hard about it. =) */
let node_vid = RegionVid { index: idx as u32 };
- match var_data[idx].classification {
- Expanding => {
- self.collect_error_for_expanding_node(
- free_regions, graph, var_data, &mut dup_vec,
- node_vid, errors);
- }
- Contracting => {
- self.collect_error_for_contracting_node(
- free_regions, graph, var_data, &mut dup_vec,
- node_vid, errors);
- }
- }
+ self.collect_error_for_expanding_node(
+ free_regions, graph, &mut dup_vec, node_vid, errors);
}
}
}
fn collect_error_for_expanding_node(&self,
free_regions: &FreeRegionMap,
graph: &RegionGraph,
- var_data: &[VarData],
dup_vec: &mut [u32],
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>)
// Errors in expanding nodes result from a lower-bound that is
// not contained by an upper-bound.
let (mut lower_bounds, lower_dup) =
- self.collect_concrete_regions(graph, var_data, node_idx,
- graph::INCOMING, dup_vec);
+ self.collect_concrete_regions(graph, node_idx, graph::INCOMING, dup_vec);
let (mut upper_bounds, upper_dup) =
- self.collect_concrete_regions(graph, var_data, node_idx,
- graph::OUTGOING, dup_vec);
+ self.collect_concrete_regions(graph, node_idx, graph::OUTGOING, dup_vec);
if lower_dup || upper_dup {
return;
upper_bounds));
}
- fn collect_error_for_contracting_node(
- &self,
- free_regions: &FreeRegionMap,
- graph: &RegionGraph,
- var_data: &[VarData],
- dup_vec: &mut [u32],
- node_idx: RegionVid,
- errors: &mut Vec<RegionResolutionError<'tcx>>)
- {
- // Errors in contracting nodes result from two upper-bounds
- // that have no intersection.
- let (upper_bounds, dup_found) =
- self.collect_concrete_regions(graph, var_data, node_idx,
- graph::OUTGOING, dup_vec);
-
- if dup_found {
- return;
- }
-
- for upper_bound_1 in &upper_bounds {
- for upper_bound_2 in &upper_bounds {
- match self.glb_concrete_regions(free_regions,
- upper_bound_1.region,
- upper_bound_2.region) {
- Ok(_) => {}
- Err(_) => {
- let origin = (*self.var_origins.borrow())[node_idx.index as usize].clone();
- debug!("region inference error at {:?} for {:?}: \
- SupSupConflict sub: {:?} sup: {:?}",
- origin, node_idx, upper_bound_1.region, upper_bound_2.region);
- errors.push(SupSupConflict(
- origin,
- upper_bound_1.origin.clone(),
- upper_bound_1.region,
- upper_bound_2.origin.clone(),
- upper_bound_2.region));
- return;
- }
- }
- }
- }
-
- self.tcx.sess.span_bug(
- (*self.var_origins.borrow())[node_idx.index as usize].span(),
- &format!("collect_error_for_contracting_node() could not find error \
- for var {:?}, upper_bounds={:?}",
- node_idx,
- upper_bounds));
- }
-
fn collect_concrete_regions(&self,
graph: &RegionGraph,
- var_data: &[VarData],
orig_node_idx: RegionVid,
dir: Direction,
dup_vec: &mut [u32])
while !state.stack.is_empty() {
let node_idx = state.stack.pop().unwrap();
- let classification = var_data[node_idx.index as usize].classification;
// check whether we've visited this node on some previous walk
if dup_vec[node_idx.index as usize] == u32::MAX {
state.dup_found = true;
}
- debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?}, \
- classification={:?})",
- orig_node_idx, node_idx, classification);
+ debug!("collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})",
+ orig_node_idx, node_idx);
// figure out the direction from which this node takes its
// values, and search for concrete regions etc in that direction
- let dir = match classification {
- Expanding => graph::INCOMING,
- Contracting => graph::OUTGOING,
- };
-
+ let dir = graph::INCOMING;
process_edges(self, &mut state, graph, node_idx, dir);
}
fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
match values[rid.index as usize] {
Value(r) => r,
- NoValue => ReEmpty, // No constraints, return ty::ReEmpty
ErrorValue => ReStatic, // Previously reported error.
}
}
use middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use std::mem;
-/// "Greatest lower bound" (common subtype)
+/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
pub struct Sub<'a, 'tcx: 'a> {
fields: CombineFields<'a, 'tcx>,
}
}
_ => {
- combine::super_combine_tys(self.fields.infcx, self, a, b)
+ try!(combine::super_combine_tys(self.fields.infcx, self, a, b));
+ Ok(a)
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use syntax::ast;
use middle::ty::{self, IntVarValue, Ty};
use rustc_data_structures::unify::UnifyKey;
-use rustc_front::hir as ast;
pub trait ToType<'tcx> {
fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
ty::TyBareFn(_, ref bfty) => bfty.abi == RustIntrinsic,
_ => return false
};
- intrinsic && self.tcx.item_name(def_id) == "transmute"
+ intrinsic && self.tcx.item_name(def_id).as_str() == "transmute"
}
fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>, id: ast::NodeId) {
pub use self::LangItem::*;
+use front::map as hir_map;
use session::Session;
use metadata::csearch::each_lang_item;
use middle::def_id::DefId;
use middle::weak_lang_items;
use util::nodemap::FnvHashMap;
-use rustc_front::attr::AttrMetaMethods;
+use syntax::ast;
+use syntax::attr::AttrMetaMethods;
use syntax::codemap::{DUMMY_SP, Span};
use syntax::parse::token::InternedString;
use rustc_front::visit::Visitor;
)*
}
-struct LanguageItemCollector<'a> {
+struct LanguageItemCollector<'a, 'tcx: 'a> {
items: LanguageItems,
+ ast_map: &'a hir_map::Map<'tcx>,
+
session: &'a Session,
item_refs: FnvHashMap<&'static str, usize>,
}
-impl<'a, 'v> Visitor<'v> for LanguageItemCollector<'a> {
+impl<'a, 'v, 'tcx> Visitor<'v> for LanguageItemCollector<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
if let Some(value) = extract(&item.attrs) {
let item_index = self.item_refs.get(&value[..]).cloned();
if let Some(item_index) = item_index {
- self.collect_item(item_index, DefId::local(item.id), item.span)
+ self.collect_item(item_index, self.ast_map.local_def_id(item.id), item.span)
}
}
}
}
-impl<'a> LanguageItemCollector<'a> {
- pub fn new(session: &'a Session) -> LanguageItemCollector<'a> {
+impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
+ pub fn new(session: &'a Session, ast_map: &'a hir_map::Map<'tcx>)
+ -> LanguageItemCollector<'a, 'tcx> {
let mut item_refs = FnvHashMap();
$( item_refs.insert($name, $variant as usize); )*
LanguageItemCollector {
session: session,
+ ast_map: ast_map,
items: LanguageItems::new(),
- item_refs: item_refs
+ item_refs: item_refs,
}
}
pub fn collect_external_language_items(&mut self) {
let crate_store = &self.session.cstore;
crate_store.iter_crate_data(|crate_number, _crate_metadata| {
- each_lang_item(crate_store, crate_number, |node_id, item_index| {
- let def_id = DefId { krate: crate_number, node: node_id };
+ each_lang_item(crate_store, crate_number, |index, item_index| {
+ let def_id = DefId { krate: crate_number, index: index };
self.collect_item(item_index, def_id, DUMMY_SP);
true
});
}
}
-pub fn extract(attrs: &[hir::Attribute]) -> Option<InternedString> {
+pub fn extract(attrs: &[ast::Attribute]) -> Option<InternedString> {
for attribute in attrs {
match attribute.value_str() {
Some(ref value) if attribute.check_name("lang") => {
return None;
}
-pub fn collect_language_items(krate: &hir::Crate,
- session: &Session) -> LanguageItems {
- let mut collector = LanguageItemCollector::new(session);
+pub fn collect_language_items(session: &Session,
+ map: &hir_map::Map)
+ -> LanguageItems {
+ let krate: &hir::Crate = map.krate();
+ let mut collector = LanguageItemCollector::new(session, map);
collector.collect(krate);
let LanguageItemCollector { mut items, .. } = collector;
weak_lang_items::check_crate(krate, session, &mut items);
BitOrTraitLangItem, "bitor", bitor_trait;
ShlTraitLangItem, "shl", shl_trait;
ShrTraitLangItem, "shr", shr_trait;
+ AddAssignTraitLangItem, "add_assign", add_assign_trait;
+ SubAssignTraitLangItem, "sub_assign", sub_assign_trait;
+ MulAssignTraitLangItem, "mul_assign", mul_assign_trait;
+ DivAssignTraitLangItem, "div_assign", div_assign_trait;
+ RemAssignTraitLangItem, "rem_assign", rem_assign_trait;
+ BitXorAssignTraitLangItem, "bitxor_assign", bitxor_assign_trait;
+ BitAndAssignTraitLangItem, "bitand_assign", bitand_assign_trait;
+ BitOrAssignTraitLangItem, "bitor_assign", bitor_assign_trait;
+ ShlAssignTraitLangItem, "shl_assign", shl_assign_trait;
+ ShrAssignTraitLangItem, "shr_assign", shr_assign_trait;
IndexTraitLangItem, "index", index_trait;
IndexMutTraitLangItem, "index_mut", index_mut_trait;
RangeStructLangItem, "range", range_struct;
EhUnwindResumeLangItem, "eh_unwind_resume", eh_unwind_resume;
MSVCTryFilterLangItem, "msvc_try_filter", msvc_try_filter;
- ExchangeHeapLangItem, "exchange_heap", exchange_heap;
OwnedBoxLangItem, "owned_box", owned_box;
PhantomDataItem, "phantom_data", phantom_data;
&*arg.pat,
|_bm, arg_id, _x, path1| {
debug!("adding argument {}", arg_id);
- let name = path1.node.name;
+ let name = path1.node;
fn_maps.add_variable(Arg(arg_id, name));
})
};
fn visit_local(ir: &mut IrMaps, local: &hir::Local) {
pat_util::pat_bindings(&ir.tcx.def_map, &*local.pat, |_, p_id, sp, path1| {
debug!("adding local variable {}", p_id);
- let name = path1.node.name;
+ let name = path1.node;
ir.add_live_node_for_node(p_id, VarDefNode(sp));
ir.add_variable(Local(LocalInfo {
id: p_id,
pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
debug!("adding local variable {} from match with bm {:?}",
p_id, bm);
- let name = path1.node.name;
+ let name = path1.node;
ir.add_live_node_for_node(p_id, VarDefNode(sp));
ir.add_variable(Local(LocalInfo {
id: p_id,
let mut call_caps = Vec::new();
ir.tcx.with_freevars(expr.id, |freevars| {
for fv in freevars {
- if let DefLocal(rv) = fv.def {
+ if let DefLocal(_, rv) = fv.def {
let fv_ln = ir.add_live_node(FreeVarNode(fv.span));
call_caps.push(CaptureInfo {ln: fv_ln,
var_nid: rv});
hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) |
hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) |
hir::ExprStruct(..) | hir::ExprRepeat(..) |
- hir::ExprParen(..) | hir::ExprInlineAsm(..) | hir::ExprBox(..) |
+ hir::ExprInlineAsm(..) | hir::ExprBox(..) |
hir::ExprRange(..) => {
visit::walk_expr(ir, expr);
}
}
fn find_loop_scope(&self,
- opt_label: Option<ast::Ident>,
+ opt_label: Option<ast::Name>,
id: NodeId,
sp: Span)
-> NodeId {
hir::ExprBreak(opt_label) => {
// Find which label this break jumps to
- let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
+ let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span);
// Now that we know the label we're going to,
// look it up in the break loop nodes table
hir::ExprAgain(opt_label) => {
// Find which label this expr continues to
- let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
+ let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span);
// Now that we know the label we're going to,
// look it up in the continue loop nodes table
}
hir::ExprIndex(ref l, ref r) |
- hir::ExprBinary(_, ref l, ref r) |
- hir::ExprBox(Some(ref l), ref r) => {
+ hir::ExprBinary(_, ref l, ref r) => {
let r_succ = self.propagate_through_expr(&**r, succ);
self.propagate_through_expr(&**l, r_succ)
}
e1.as_ref().map_or(succ, |e| self.propagate_through_expr(&**e, succ))
}
- hir::ExprBox(None, ref e) |
+ hir::ExprBox(ref e) |
hir::ExprAddrOf(_, ref e) |
hir::ExprCast(ref e, _) |
- hir::ExprUnary(_, ref e) |
- hir::ExprParen(ref e) => {
+ hir::ExprUnary(_, ref e) => {
self.propagate_through_expr(&**e, succ)
}
fn access_path(&mut self, expr: &Expr, succ: LiveNode, acc: u32)
-> LiveNode {
match self.ir.tcx.def_map.borrow().get(&expr.id).unwrap().full_def() {
- DefLocal(nid) => {
+ DefLocal(_, nid) => {
let ln = self.live_node(expr.id, expr.span);
if acc != 0 {
self.init_from_succ(ln, succ);
fn check_expr(this: &mut Liveness, expr: &Expr) {
match expr.node {
- hir::ExprAssign(ref l, ref r) => {
+ hir::ExprAssign(ref l, _) => {
this.check_lvalue(&**l);
- this.visit_expr(&**r);
visit::walk_expr(this, expr);
}
hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) |
hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) |
hir::ExprBlock(..) | hir::ExprAddrOf(..) |
- hir::ExprStruct(..) | hir::ExprRepeat(..) | hir::ExprParen(..) |
+ hir::ExprStruct(..) | hir::ExprRepeat(..) |
hir::ExprClosure(..) | hir::ExprPath(..) | hir::ExprBox(..) |
hir::ExprRange(..) => {
visit::walk_expr(this, expr);
fn check_lvalue(&mut self, expr: &Expr) {
match expr.node {
hir::ExprPath(..) => {
- if let DefLocal(nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
- .unwrap()
- .full_def() {
+ if let DefLocal(_, nid) = self.ir.tcx.def_map.borrow().get(&expr.id)
+ .unwrap()
+ .full_def() {
// Assignment to an immutable variable or argument: only legal
// if there is no later assignment. If this local is actually
// mutable, then check for a reassignment to flag the mutability
|_bm, p_id, sp, path1| {
let var = self.variable(p_id, sp);
// Ignore unused self.
- let ident = path1.node;
- if ident.name != special_idents::self_.name {
+ let name = path1.node;
+ if name != special_idents::self_.name {
self.warn_about_unused(sp, p_id, entry_ln, var);
}
})
fn from_local(tcx: &ty::ctxt, id: ast::NodeId) -> MutabilityCategory {
let ret = match tcx.map.get(id) {
- ast_map::NodeLocal(p) | ast_map::NodeArg(p) => match p.node {
+ ast_map::NodeLocal(p) => match p.node {
hir::PatIdent(bind_mode, _, _) => {
if bind_mode == hir::BindByValue(hir::MutMutable) {
McDeclared
expr.id,
expr,
base_cmt);
- Ok(self.cat_field(expr, base_cmt, f_name.node.name, expr_ty))
+ Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
}
hir::ExprTupField(ref base, idx) => {
self.cat_def(expr.id, expr.span, expr_ty, def)
}
- hir::ExprParen(ref e) => {
- self.cat_expr(&**e)
- }
-
hir::ExprAddrOf(..) | hir::ExprCall(..) |
hir::ExprAssign(..) | hir::ExprAssignOp(..) |
hir::ExprClosure(..) | hir::ExprRet(..) |
}
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
- def::DefTyParam(..) | def::DefRegion(_) |
+ def::DefTyParam(..) |
def::DefLabel(_) | def::DefSelfTy(..) |
def::DefAssociatedTy(..) => {
Ok(Rc::new(cmt_ {
}))
}
- def::DefUpvar(var_id, _, fn_node_id) => {
+ def::DefUpvar(_, var_id, _, fn_node_id) => {
let ty = try!(self.node_ty(fn_node_id));
match ty.sty {
ty::TyClosure(closure_id, _) => {
}
}
- def::DefLocal(vid) => {
+ def::DefLocal(_, vid) => {
Ok(Rc::new(cmt_ {
id: id,
span: span,
// {f1: p1, ..., fN: pN}
for fp in field_pats {
let field_ty = try!(self.pat_ty(&*fp.node.pat)); // see (*2)
- let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.ident.name, field_ty);
+ let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty);
try!(self.cat_pattern_(cmt_field, &*fp.node.pat, op));
}
}
"non-lvalue".to_string()
}
cat_local(vid) => {
- match tcx.map.find(vid) {
- Some(ast_map::NodeArg(_)) => {
- "argument".to_string()
- }
- _ => "local variable".to_string()
+ if tcx.map.is_argument(vid) {
+ "argument".to_string()
+ } else {
+ "local variable".to_string()
}
}
cat_deref(_, _, pk) => {
use util::nodemap::FnvHashMap;
use syntax::ast;
+use syntax::ext::mtwt;
use rustc_front::hir;
use rustc_front::util::walk_pat;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax::codemap::{respan, Span, Spanned, DUMMY_SP};
-pub type PatIdMap = FnvHashMap<ast::Ident, ast::NodeId>;
+pub type PatIdMap = FnvHashMap<ast::Name, ast::NodeId>;
// This is used because same-named variables in alternative patterns need to
// use the NodeId of their namesake in the first pattern.
pub fn pat_id_map(dm: &DefMap, pat: &hir::Pat) -> PatIdMap {
let mut map = FnvHashMap();
- pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
- map.insert(path1.node, p_id);
+ pat_bindings_hygienic(dm, pat, |_bm, p_id, _s, path1| {
+ map.insert(mtwt::resolve(path1.node), p_id);
});
map
}
/// Call `it` on every "binding" in a pattern, e.g., on `a` in
/// `match foo() { Some(a) => (), None => () }`
pub fn pat_bindings<I>(dm: &DefMap, pat: &hir::Pat, mut it: I) where
- I: FnMut(hir::BindingMode, ast::NodeId, Span, &hir::SpannedIdent),
+ I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Name>),
{
walk_pat(pat, |p| {
match p.node {
hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => {
- it(binding_mode, p.id, p.span, pth);
+ it(binding_mode, p.id, p.span, &respan(pth.span, pth.node.name));
+ }
+ _ => {}
+ }
+ true
+ });
+}
+
+pub fn pat_bindings_hygienic<I>(dm: &DefMap, pat: &hir::Pat, mut it: I) where
+ I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<ast::Ident>),
+{
+ walk_pat(pat, |p| {
+ match p.node {
+ hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => {
+ it(binding_mode, p.id, p.span, &respan(pth.span, pth.node));
}
_ => {}
}
contains_bindings
}
-pub fn simple_identifier<'a>(pat: &'a hir::Pat) -> Option<&'a ast::Ident> {
+pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> {
match pat.node {
hir::PatIdent(hir::BindByValue(_), ref path1, None) => {
- Some(&path1.node)
+ Some(path1.node.name)
}
_ => {
None
tcx.with_path(id, |path| hir::Path {
global: false,
segments: path.last().map(|elem| hir::PathSegment {
- identifier: ast::Ident::new(elem.name()),
+ identifier: ast::Ident::with_empty_ctxt(elem.name()),
parameters: hir::PathParameters::none(),
}).into_iter().collect(),
span: DUMMY_SP,
}
/// Return variants that are necessary to exist for the pattern to match.
-pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<ast::NodeId> {
+pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec<DefId> {
let mut variants = vec![];
walk_pat(pat, |p| {
match p.node {
hir::PatStruct(..) => {
match dm.borrow().get(&p.id) {
Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => {
- variants.push(id.node);
+ variants.push(id);
}
_ => ()
}
use front::map as ast_map;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::ty;
use middle::privacy;
use session::config;
use std::collections::HashSet;
use syntax::abi;
use syntax::ast;
+use syntax::attr;
use rustc_front::hir;
-use rustc_front::attr;
use rustc_front::visit::Visitor;
use rustc_front::visit;
generics_require_inlining(&sig.generics) {
return true
}
- if impl_src.is_local() {
- {
- match tcx.map.find(impl_src.node) {
- Some(ast_map::NodeItem(item)) => {
- item_might_be_inlined(&*item)
- }
- Some(..) | None => {
- tcx.sess.span_bug(impl_item.span, "impl did is not an item")
- }
- }
+ if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_src) {
+ match tcx.map.find(impl_node_id) {
+ Some(ast_map::NodeItem(item)) =>
+ item_might_be_inlined(&*item),
+ Some(..) | None =>
+ tcx.sess.span_bug(impl_item.span, "impl did is not an item")
}
} else {
- tcx.sess.span_bug(impl_item.span, "found a foreign impl as a parent \
- of a local method")
+ tcx.sess.span_bug(impl_item.span, "found a foreign impl as a parent of a local method")
}
}
};
let def_id = def.def_id();
- if def_id.is_local() {
+ if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
if self.def_id_represents_local_inlined_item(def_id) {
- self.worklist.push(def_id.node)
+ self.worklist.push(node_id);
} else {
match def {
// If this path leads to a constant, then we need to
// recurse into the constant to continue finding
// items that are reachable.
def::DefConst(..) | def::DefAssociatedConst(..) => {
- self.worklist.push(def_id.node);
+ self.worklist.push(node_id);
}
// If this wasn't a static, then the destination is
// surely reachable.
_ => {
- self.reachable_symbols.insert(def_id.node);
+ self.reachable_symbols.insert(node_id);
}
}
}
let def_id = self.tcx.tables.borrow().method_map[&method_call].def_id;
match self.tcx.impl_or_trait_item(def_id).container() {
ty::ImplContainer(_) => {
- if def_id.is_local() {
+ if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
if self.def_id_represents_local_inlined_item(def_id) {
- self.worklist.push(def_id.node)
+ self.worklist.push(node_id)
}
- self.reachable_symbols.insert(def_id.node);
+ self.reachable_symbols.insert(node_id);
}
}
ty::TraitContainer(_) => {}
// Returns true if the given def ID represents a local item that is
// eligible for inlining and false otherwise.
fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
- if def_id.krate != LOCAL_CRATE {
- return false
- }
+ let node_id = match self.tcx.map.as_local_node_id(def_id) {
+ Some(node_id) => node_id,
+ None => { return false; }
+ };
- let node_id = def_id.node;
match self.tcx.map.find(node_id) {
Some(ast_map::NodeItem(item)) => {
match item.node {
// Check the impl. If the generics on the self
// type of the impl require inlining, this method
// does too.
- assert!(impl_did.is_local());
- match self.tcx
- .map
- .expect_item(impl_did.node)
- .node {
+ let impl_node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
+ match self.tcx.map.expect_item(impl_node_id).node {
hir::ItemImpl(_, _, ref generics, _, _, _) => {
generics_require_inlining(generics)
}
drop_trait.for_each_impl(self.tcx, |drop_impl| {
for destructor in &self.tcx.impl_items.borrow()[&drop_impl] {
let destructor_did = destructor.def_id();
- if destructor_did.is_local() {
- self.reachable_symbols.insert(destructor_did.node);
+ if let Some(destructor_node_id) = self.tcx.map.as_local_node_id(destructor_did) {
+ self.reachable_symbols.insert(destructor_node_id);
}
}
})
}
for (_, item) in tcx.lang_items.items() {
match *item {
- Some(did) if did.is_local() => {
- reachable_context.worklist.push(did.node);
+ Some(did) => {
+ if let Some(node_id) = tcx.map.as_local_node_id(did) {
+ reachable_context.worklist.push(node_id);
+ }
}
_ => {}
}
self.code_extents.borrow()[e.0 as usize]
}
pub fn each_encl_scope<E>(&self, mut e:E) where E: FnMut(&CodeExtent, &CodeExtent) {
- for child_id in (1..self.code_extents.borrow().len()) {
+ for child_id in 1..self.code_extents.borrow().len() {
let child = CodeExtent(child_id as u32);
if let Some(parent) = self.opt_encl_scope(child) {
e(&child, &parent)
}
visitor.visit_stmt(&**statement)
}
- visit::walk_expr_opt(visitor, &blk.expr)
+ walk_list!(visitor, visit_expr, &blk.expr);
}
visitor.cx = prev_cx;
visitor, &**subexpr, blk_id);
}
}
- hir::ExprUnary(hir::UnUniq, ref subexpr) => {
- record_rvalue_scope_if_borrow_expr(visitor, &**subexpr, blk_id);
- }
- hir::ExprCast(ref subexpr, _) |
- hir::ExprParen(ref subexpr) => {
+ hir::ExprCast(ref subexpr, _) => {
record_rvalue_scope_if_borrow_expr(visitor, &**subexpr, blk_id)
}
hir::ExprBlock(ref block) => {
hir::ExprUnary(hir::UnDeref, ref subexpr) |
hir::ExprField(ref subexpr, _) |
hir::ExprTupField(ref subexpr, _) |
- hir::ExprIndex(ref subexpr, _) |
- hir::ExprParen(ref subexpr) => {
+ hir::ExprIndex(ref subexpr, _) => {
expr = &**subexpr;
}
_ => {
trait_ref_hack: bool,
// List of labels in the function/method currently under analysis.
- labels_in_fn: Vec<(ast::Ident, Span)>,
+ labels_in_fn: Vec<(ast::Name, Span)>,
}
enum ScopeChain<'a> {
fn visit_ty(&mut self, ty: &hir::Ty) {
match ty.node {
hir::TyBareFn(ref c) => {
- visit::walk_lifetime_decls_helper(self, &c.lifetimes);
self.with(LateScope(&c.lifetimes, self.scope), |old_scope, this| {
// a bare fn has no bounds, so everything
// contained within is scoped within its binder.
|_, this| visit::walk_block(this, b));
}
- fn visit_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
+ fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
if lifetime_ref.name == special_idents::static_lifetime.name {
self.insert_lifetime(lifetime_ref, DefStaticRegion);
return;
fn visit_generics(&mut self, generics: &hir::Generics) {
for ty_param in generics.ty_params.iter() {
- visit::walk_ty_param_bounds_helper(self, &ty_param.bounds);
+ walk_list!(self, visit_ty_param_bound, &ty_param.bounds);
match ty_param.default {
Some(ref ty) => self.visit_ty(&**ty),
None => {}
|old_scope, this| {
this.check_lifetime_defs(old_scope, bound_lifetimes);
this.visit_ty(&**bounded_ty);
- visit::walk_ty_param_bounds_helper(this, bounds);
+ walk_list!(this, visit_ty_param_bound, bounds);
});
self.trait_ref_hack = false;
result
} else {
self.visit_ty(&**bounded_ty);
- visit::walk_ty_param_bounds_helper(self, bounds);
+ walk_list!(self, visit_ty_param_bound, bounds);
}
}
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
ref bounds,
.. }) => {
- self.visit_lifetime_ref(lifetime);
+ self.visit_lifetime(lifetime);
for bound in bounds {
- self.visit_lifetime_ref(bound);
+ self.visit_lifetime(bound);
}
}
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{ id,
sess: &Session, name: ast::Name, orig: Original, shadower: Shadower) {
if let (ShadowKind::Lifetime, ShadowKind::Lifetime) = (orig.kind, shadower.kind) {
// lifetime/lifetime shadowing is an error
- sess.span_err(shadower.span,
- &format!("{} name `{}` shadows a \
- {} name that is already in scope",
- shadower.kind.desc(), name, orig.kind.desc()));
+ span_err!(sess, shadower.span, E0496,
+ "{} name `{}` shadows a \
+ {} name that is already in scope",
+ shadower.kind.desc(), name, orig.kind.desc());
} else {
// shadowing involving a label is only a warning, due to issues with
// labels and lifetimes not being macro-hygienic.
struct GatherLabels<'a> {
sess: &'a Session,
scope: Scope<'a>,
- labels_in_fn: &'a mut Vec<(ast::Ident, Span)>,
+ labels_in_fn: &'a mut Vec<(ast::Name, Span)>,
}
let mut gather = GatherLabels {
if let Some(label) = expression_label(ex) {
for &(prior, prior_span) in &self.labels_in_fn[..] {
// FIXME (#24278): non-hygienic comparison
- if label.name == prior.name {
+ if label == prior {
signal_shadowing_problem(self.sess,
- label.name,
+ label,
original_label(prior_span),
shadower_label(ex.span));
}
}
}
- fn expression_label(ex: &hir::Expr) -> Option<ast::Ident> {
+ fn expression_label(ex: &hir::Expr) -> Option<ast::Name> {
match ex.node {
hir::ExprWhile(_, _, Some(label)) |
- hir::ExprLoop(_, Some(label)) => Some(label),
+ hir::ExprLoop(_, Some(label)) => Some(label.name),
_ => None,
}
}
fn check_if_label_shadows_lifetime<'a>(sess: &'a Session,
mut scope: Scope<'a>,
- label: ast::Ident,
+ label: ast::Name,
label_span: Span) {
loop {
match *scope {
LateScope(lifetimes, s) => {
for lifetime_def in lifetimes {
// FIXME (#24278): non-hygienic comparison
- if label.name == lifetime_def.lifetime.name {
+ if label == lifetime_def.lifetime.name {
signal_shadowing_problem(
sess,
- label.name,
+ label,
original_lifetime(&lifetime_def.lifetime),
shadower_label(label_span));
return;
{
for &(label, label_span) in &self.labels_in_fn {
// FIXME (#24278): non-hygienic comparison
- if lifetime.name == label.name {
+ if lifetime.name == label {
signal_shadowing_problem(self.sess,
lifetime.name,
original_label(label_span),
FreeLifetimeCollector { early_bound: &mut early_bound,
late_bound: &mut late_bound };
for ty_param in generics.ty_params.iter() {
- visit::walk_ty_param_bounds_helper(&mut collector, &ty_param.bounds);
+ walk_list!(&mut collector, visit_ty_param_bound, &ty_param.bounds);
}
for predicate in &generics.where_clause.predicates {
match predicate {
ref bounded_ty,
..}) => {
collector.visit_ty(&**bounded_ty);
- visit::walk_ty_param_bounds_helper(&mut collector, bounds);
+ walk_list!(&mut collector, visit_ty_param_bound, bounds);
}
&hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
ref bounds,
..}) => {
- collector.visit_lifetime_ref(lifetime);
+ collector.visit_lifetime(lifetime);
for bound in bounds {
- collector.visit_lifetime_ref(bound);
+ collector.visit_lifetime(bound);
}
}
&hir::WherePredicate::EqPredicate(_) => unimplemented!()
}
impl<'a, 'v> Visitor<'v> for FreeLifetimeCollector<'a> {
- fn visit_lifetime_ref(&mut self, lifetime_ref: &hir::Lifetime) {
+ fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) {
shuffle(self.early_bound, self.late_bound,
lifetime_ref.name);
}
//! A pass that annotates every item and method with its stability level,
//! propagating default levels lexically from parent to children ast nodes.
+pub use self::StabilityLevel::*;
+
use session::Session;
use lint;
+use metadata::cstore::LOCAL_CRATE;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::{CRATE_DEF_INDEX, DefId};
use middle::ty;
use middle::privacy::PublicItems;
use metadata::csearch;
use syntax::parse::token::InternedString;
use syntax::codemap::{Span, DUMMY_SP};
use syntax::ast;
-use syntax::ast::NodeId;
+use syntax::ast::{NodeId, Attribute};
use syntax::feature_gate::{GateIssue, emit_feature_err};
+use syntax::attr::{self, Stability, AttrMetaMethods};
use util::nodemap::{DefIdMap, FnvHashSet, FnvHashMap};
use rustc_front::hir;
-use rustc_front::hir::{FnDecl, Attribute, Block, Crate, Item, Generics, StructField, Variant};
-use rustc_front::attr::{self, Stability, AttrMetaMethods};
+use rustc_front::hir::{FnDecl, Block, Crate, Item, Generics, StructField, Variant};
use rustc_front::visit::{self, FnKind, Visitor};
use std::mem::replace;
use std::cmp::Ordering;
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Copy, Debug, Eq, Hash)]
+pub enum StabilityLevel {
+ Unstable,
+ Stable,
+}
+
+impl StabilityLevel {
+ pub fn from_attr_level(level: &attr::StabilityLevel) -> Self {
+ if level.is_stable() { Stable } else { Unstable }
+ }
+}
+
/// A stability index, giving the stability level for items and methods.
pub struct Index<'tcx> {
/// This is mostly a cache, except the stabilities of local items
// if parent is deprecated and we're not, inherit this by merging
// deprecated_since and its reason.
if let Some(parent_stab) = self.parent {
- if parent_stab.deprecated_since.is_some()
- && stab.deprecated_since.is_none() {
- stab.deprecated_since = parent_stab.deprecated_since.clone();
- stab.reason = parent_stab.reason.clone();
+ if parent_stab.depr.is_some()
+ && stab.depr.is_none() {
+ stab.depr = parent_stab.depr.clone()
}
}
// Check if deprecated_since < stable_since. If it is,
// this is *almost surely* an accident.
- let deprecated_predates_stable = match (stab.deprecated_since.as_ref(),
- stab.since.as_ref()) {
- (Some(dep_since), Some(stab_since)) => {
+ let deprecated_predates_stable = match (&stab.depr, &stab.level) {
+ (&Some(attr::Deprecation {since: ref dep_since, ..}),
+ &attr::Stable {since: ref stab_since}) => {
// explicit version of iter::order::lt to handle parse errors properly
let mut is_less = false;
for (dep_v, stab_v) in dep_since.split(".").zip(stab_since.split(".")) {
"An API can't be stabilized after it is deprecated");
}
- self.index.map.insert(DefId::local(id), Some(stab));
+ let def_id = self.tcx.map.local_def_id(id);
+ self.index.map.insert(def_id, Some(stab));
// Don't inherit #[stable(feature = "rust1", since = "1.0.0")]
- if stab.level != attr::Stable {
+ if !stab.level.is_stable() {
let parent = replace(&mut self.parent, Some(stab));
f(self);
self.parent = parent;
use_parent, self.parent);
if use_parent {
if let Some(stab) = self.parent {
- self.index.map.insert(DefId::local(id), Some(stab));
+ let def_id = self.tcx.map.local_def_id(id);
+ self.index.map.insert(def_id, Some(stab));
} else if self.index.staged_api[&LOCAL_CRATE] && required
&& self.export_map.contains(&id)
&& !self.tcx.sess.opts.test {
|v| visit::walk_item(v, i), required);
if let hir::ItemStruct(ref sd, _) = i.node {
- sd.ctor_id.map(|id| {
- self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
- });
+ if !sd.is_struct() {
+ self.annotate(sd.id(), true, &i.attrs, i.span, |_| {}, true)
+ }
}
}
|v| visit::walk_impl_item(v, ii), true);
}
- fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
- self.annotate(var.node.id, true, &var.node.attrs, var.span,
- |v| visit::walk_variant(v, var, g), true)
+ fn visit_variant(&mut self, var: &Variant, g: &'v Generics, item_id: NodeId) {
+ self.annotate(var.node.data.id(), true, &var.node.attrs, var.span,
+ |v| visit::walk_variant(v, var, g, item_id), true)
}
fn visit_struct_field(&mut self, s: &StructField) {
for attr in &krate.attrs {
if &attr.name()[..] == "staged_api" {
match attr.node.value.node {
- hir::MetaWord(_) => {
+ ast::MetaWord(_) => {
attr::mark_used(attr);
is_staged_api = true;
}
/// features and possibly prints errors. Returns a list of all
/// features used.
pub fn check_unstable_api_usage(tcx: &ty::ctxt)
- -> FnvHashMap<InternedString, attr::StabilityLevel> {
+ -> FnvHashMap<InternedString, StabilityLevel> {
let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
// Put the active features into a map for quick lookup
let mut checker = Checker {
tcx: tcx,
active_features: active_features,
- used_features: FnvHashMap()
+ used_features: FnvHashMap(),
+ in_skip_block: 0,
};
let krate = tcx.map.krate();
struct Checker<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
active_features: FnvHashSet<InternedString>,
- used_features: FnvHashMap<InternedString, attr::StabilityLevel>
+ used_features: FnvHashMap<InternedString, StabilityLevel>,
+ // Within a block where feature gate checking can be skipped.
+ in_skip_block: u32,
}
impl<'a, 'tcx> Checker<'a, 'tcx> {
fn check(&mut self, id: DefId, span: Span, stab: &Option<&Stability>) {
// Only the cross-crate scenario matters when checking unstable APIs
let cross_crate = !id.is_local();
- if !cross_crate { return }
+ if !cross_crate {
+ return
+ }
+
+ // We don't need to check for stability - presumably compiler generated code.
+ if self.in_skip_block > 0 {
+ return;
+ }
match *stab {
- Some(&Stability { level: attr::Unstable, ref feature, ref reason, issue, .. }) => {
- self.used_features.insert(feature.clone(), attr::Unstable);
+ Some(&Stability { level: attr::Unstable {ref reason, issue}, ref feature, .. }) => {
+ self.used_features.insert(feature.clone(), Unstable);
if !self.active_features.contains(feature) {
let msg = match *reason {
&feature, &r),
None => format!("use of unstable library feature '{}'", &feature)
};
-
emit_feature_err(&self.tcx.sess.parse_sess.span_diagnostic,
- &feature, span, GateIssue::Library(issue), &msg);
+ &feature, span, GateIssue::Library(Some(issue)), &msg);
}
}
- Some(&Stability { level, ref feature, .. }) => {
- self.used_features.insert(feature.clone(), level);
+ Some(&Stability { ref level, ref feature, .. }) => {
+ self.used_features.insert(feature.clone(), StabilityLevel::from_attr_level(level));
// Stable APIs are always ok to call and deprecated APIs are
// handled by a lint.
// When compiling with --test we don't enforce stability on the
// compiler-generated test module, demarcated with `DUMMY_SP` plus the
// name `__test`
- if item.span == DUMMY_SP && item.ident.name == "__test" { return }
+ if item.span == DUMMY_SP && item.name.as_str() == "__test" { return }
check_item(self.tcx, item, true,
&mut |id, sp, stab| self.check(id, sp, stab));
visit::walk_path(self, path)
}
+ fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
+ check_path_list_item(self.tcx, item,
+ &mut |id, sp, stab| self.check(id, sp, stab));
+ visit::walk_path_list_item(self, prefix, item)
+ }
+
fn visit_pat(&mut self, pat: &hir::Pat) {
check_pat(self.tcx, pat,
&mut |id, sp, stab| self.check(id, sp, stab));
visit::walk_pat(self, pat)
}
+
+ fn visit_block(&mut self, b: &hir::Block) {
+ let old_skip_count = self.in_skip_block;
+ match b.rules {
+ hir::BlockCheckMode::PushUnstableBlock => {
+ self.in_skip_block += 1;
+ }
+ hir::BlockCheckMode::PopUnstableBlock => {
+ self.in_skip_block = self.in_skip_block.checked_sub(1).unwrap();
+ }
+ _ => {}
+ }
+ visit::walk_block(self, b);
+ self.in_skip_block = old_skip_count;
+ }
}
/// Helper for discovering nodes to check for stability
Some(cnum) => cnum,
None => return,
};
- let id = DefId { krate: cnum, node: ast::CRATE_NODE_ID };
+ let id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
maybe_do_stability_check(tcx, id, item.span, cb);
}
for impl_item in impl_items {
let item = trait_items.iter().find(|item| {
- item.name() == impl_item.ident.name
+ item.name() == impl_item.name
}).unwrap();
if warn_about_defns {
maybe_do_stability_check(tcx, item.def_id(), impl_item.span, cb);
hir::ExprField(ref base_e, ref field) => {
span = field.span;
match tcx.expr_ty_adjusted(base_e).sty {
- ty::TyStruct(def, _) => def.struct_variant().field_named(field.node.name).did,
+ ty::TyStruct(def, _) => def.struct_variant().field_named(field.node).did,
_ => tcx.sess.span_bug(e.span,
"stability::check_expr: named field access on non-struct")
}
// in the construction expression.
for field in expr_fields {
let did = def.struct_variant()
- .field_named(field.ident.node.name)
+ .field_named(field.name.node)
.did;
maybe_do_stability_check(tcx, did, field.span, cb);
}
cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
match tcx.def_map.borrow().get(&id).map(|d| d.full_def()) {
Some(def::DefPrimTy(..)) => {}
+ Some(def::DefSelfTy(..)) => {}
Some(def) => {
maybe_do_stability_check(tcx, def.def_id(), path.span, cb);
}
None => {}
}
+}
+pub fn check_path_list_item(tcx: &ty::ctxt, item: &hir::PathListItem,
+ cb: &mut FnMut(DefId, Span, &Option<&Stability>)) {
+ match tcx.def_map.borrow().get(&item.node.id()).map(|d| d.full_def()) {
+ Some(def::DefPrimTy(..)) => {}
+ Some(def) => {
+ maybe_do_stability_check(tcx, def.def_id(), item.span, cb);
+ }
+ None => {}
+ }
}
pub fn check_pat(tcx: &ty::ctxt, pat: &hir::Pat,
// Foo { a, b, c }
hir::PatStruct(_, ref pat_fields, _) => {
for field in pat_fields {
- let did = v.field_named(field.node.ident.name).did;
+ let did = v.field_named(field.node.name).did;
maybe_do_stability_check(tcx, did, field.span, cb);
}
}
/// libraries, identify activated features that don't exist and error about them.
pub fn check_unused_or_stable_features(sess: &Session,
lib_features_used: &FnvHashMap<InternedString,
- attr::StabilityLevel>) {
+ StabilityLevel>) {
let ref declared_lib_features = sess.features.borrow().declared_lib_features;
let mut remaining_lib_features: FnvHashMap<InternedString, Span>
= declared_lib_features.clone().into_iter().collect();
for (used_lib_feature, level) in lib_features_used {
match remaining_lib_features.remove(used_lib_feature) {
Some(span) => {
- if *level == attr::Stable {
+ if *level == Stable {
sess.add_lint(lint::builtin::STABLE_FEATURES,
ast::CRATE_NODE_ID,
span,
use super::project;
use super::util;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
use middle::subst::{Subst, Substs, TypeSpace};
use middle::ty::{self, ToPolyTraitRef, Ty};
use middle::infer::{self, InferCtxt};
use std::fmt;
use syntax::codemap::Span;
-use rustc_front::attr::{AttributeMethods, AttrMetaMethods};
+use syntax::attr::{AttributeMethods, AttrMetaMethods};
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TraitErrorKey<'tcx> {
is_warning, infcx.tcx.sess, obligation.cause.span, E0276,
"the requirement `{}` appears on the impl \
method but not on the corresponding trait method",
- obligation.predicate);;
+ obligation.predicate);
} else {
match obligation.predicate {
ty::Predicate::Trait(ref trait_predicate) => {
}
ty::Predicate::ObjectSafe(trait_def_id) => {
+ let violations = object_safety_violations(
+ infcx.tcx, trait_def_id);
report_object_safety_error(infcx.tcx,
obligation.cause.span,
trait_def_id,
+ violations,
is_warning);
note_obligation_cause(infcx, obligation);
}
}
TraitNotObjectSafe(did) => {
- report_object_safety_error(infcx.tcx, obligation.cause.span, did, is_warning);
+ let violations = object_safety_violations(infcx.tcx, did);
+ report_object_safety_error(infcx.tcx, obligation.cause.span, did,
+ violations, is_warning);
note_obligation_cause(infcx, obligation);
}
}
pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
span: Span,
trait_def_id: DefId,
+ violations: Vec<ObjectSafetyViolation>,
is_warning: bool)
{
span_err_or_warn!(
tcx.item_path_str(trait_def_id));
let mut reported_violations = FnvHashSet();
- for violation in object_safety_violations(tcx, trait_def_id) {
+ for violation in violations {
if !reported_violations.insert(violation.clone()) {
continue;
}
if !infcx.tcx.sess.has_errors() {
span_err!(infcx.tcx.sess, obligation.cause.span, E0284,
"type annotations required: cannot resolve `{}`",
- predicate);;
+ predicate);
note_obligation_cause(infcx, obligation);
}
}
pub use self::project::normalize;
pub use self::project::Normalized;
pub use self::object_safety::is_object_safe;
+pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::object_safety_violations;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::object_safety::MethodViolationCode;
use middle::def_id::DefId;
use middle::subst::{self, SelfSpace, TypeSpace};
use middle::traits;
-use middle::ty::{self, ToPolyTraitRef, Ty};
+use middle::ty::{self, HasTypeFlags, ToPolyTraitRef, Ty};
use std::rc::Rc;
use syntax::ast;
result
}
+/// Returns the object safety violations that affect
+/// astconv - currently, Self in supertraits. This is needed
+/// because `object_safety_violations` can't be used during
+/// type collection.
+pub fn astconv_object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
+ trait_def_id: DefId)
+ -> Vec<ObjectSafetyViolation<'tcx>>
+{
+ let mut violations = vec![];
+
+ if supertraits_reference_self(tcx, trait_def_id) {
+ violations.push(ObjectSafetyViolation::SupertraitSelf);
+ }
+
+ debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
+ trait_def_id,
+ violations);
+
+ violations
+}
+
pub fn object_safety_violations<'tcx>(tcx: &ty::ctxt<'tcx>,
trait_def_id: DefId)
-> Vec<ObjectSafetyViolation<'tcx>>
violations
}
-fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
- trait_def_id: DefId)
- -> bool
+pub fn supertraits_reference_self<'tcx>(tcx: &ty::ctxt<'tcx>,
+ trait_def_id: DefId)
+ -> bool
{
let trait_def = tcx.lookup_trait_def(trait_def_id);
let trait_ref = trait_def.trait_ref.clone();
data.0.trait_ref.substs.types.get_slice(TypeSpace)
.iter()
.cloned()
- .any(is_self)
+ .any(|t| t.has_self_ty())
}
ty::Predicate::Projection(..) |
ty::Predicate::WellFormed(..) |
.any(|predicate| {
match predicate {
ty::Predicate::Trait(ref trait_pred) if trait_pred.def_id() == sized_def_id => {
- is_self(trait_pred.0.self_ty())
+ trait_pred.0.self_ty().is_self()
}
ty::Predicate::Projection(..) |
ty::Predicate::Trait(..) |
error
}
-
-fn is_self<'tcx>(ty: Ty<'tcx>) -> bool {
- match ty.sty {
- ty::TyParam(ref data) => data.space == subst::SelfSpace,
- _ => false,
- }
-}
use super::object_safety;
use super::util;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::infer;
use middle::infer::{InferCtxt, TypeFreshener};
use middle::subst::{Subst, Substs, TypeSpace};
// (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
ty::TyTuple(ref tys) => ok_if(tys.clone()),
- ty::TyClosure(def_id, ref substs) => {
+ ty::TyClosure(_, ref substs) => {
// FIXME -- This case is tricky. In the case of by-ref
// closures particularly, we need the results of
// inference to decide how to reflect the type of each
// captures are by value. Really what we ought to do
// is reserve judgement and then intertwine this
// analysis with closure inference.
- assert_eq!(def_id.krate, LOCAL_CRATE);
// Unboxed closures shouldn't be
// implicitly copyable
tys.clone()
}
- ty::TyClosure(def_id, ref substs) => {
+ ty::TyClosure(_, ref substs) => {
// FIXME(#27086). We are invariant w/r/t our
// substs.func_substs, but we don't see them as
// constituent types; this seems RIGHT but also like
// OIBIT interact? That is, there is no way to say
// "make me invariant with respect to this TYPE, but
// do not act as though I can reach it"
- assert_eq!(def_id.krate, LOCAL_CRATE);
substs.upvar_tys.clone()
}
/// errors as if there is no applicable impl, but rather report
/// errors are about mismatched argument types.
///
- /// Here is an example. Imagine we have an closure expression
+ /// Here is an example. Imagine we have a closure expression
/// and we desugared it so that the type of the expression is
/// `Closure`, and `Closure` expects an int as argument. Then it
/// is "as if" the compiler generated this impl:
.collect()
}
-/// Given an trait `trait_ref`, returns the number of vtable entries
+/// Given a trait `trait_ref`, returns the number of vtable entries
/// that come from `trait_ref`, excluding its supertraits. Used in
/// computing the vtable base for an upcast trait of a trait object.
pub fn count_own_vtable_entries<'tcx>(tcx: &ty::ctxt<'tcx>,
///
/// 1. The simplest cases are where the pointer is not adjusted fat vs thin.
/// Here the pointer will be dereferenced N times (where a dereference can
-/// happen to to raw or borrowed pointers or any smart pointer which implements
+/// happen to raw or borrowed pointers or any smart pointer which implements
/// Deref, including Box<_>). The number of dereferences is given by
/// `autoderefs`. It can then be auto-referenced zero or one times, indicated
/// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is
use middle::ty::{self, Ty};
-use rustc_front::hir as ast;
+use syntax::ast;
/// Types that are represented as ints.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
use std::fmt;
use std::ops;
-use rustc_front::hir;
+use syntax::ast;
/// Type contents is how the type checker reasons about kinds.
/// They track what kinds of things are found within a type. You can
let result = match ty.sty {
// usize and isize are ffi-unsafe
- ty::TyUint(hir::TyUs) | ty::TyInt(hir::TyIs) => {
+ ty::TyUint(ast::TyUs) | ty::TyInt(ast::TyIs) => {
TC::None
}
use front::map as ast_map;
use session::Session;
use lint;
+use metadata::csearch;
use middle;
use middle::def::DefMap;
use middle::def_id::DefId;
use std::hash::{Hash, Hasher};
use std::rc::Rc;
use syntax::abi;
-use syntax::ast::{Name, NodeId};
+use syntax::ast::{self, Name, NodeId};
+use syntax::attr;
use syntax::parse::token::special_idents;
use rustc_front::hir;
-use rustc_front::attr;
/// Internal storage
pub struct CtxtArenas<'tcx> {
closure_kinds: DefIdMap(),
}
}
+
+ pub fn closure_kind(this: &RefCell<Self>,
+ tcx: &ty::ctxt<'tcx>,
+ def_id: DefId)
+ -> ty::ClosureKind {
+ // If this is a local def-id, it should be inserted into the
+ // tables by typeck; else, it will be retreived from
+ // the external crate metadata.
+ if let Some(&kind) = this.borrow().closure_kinds.get(&def_id) {
+ return kind;
+ }
+
+ let kind = csearch::closure_kind(tcx, def_id);
+ this.borrow_mut().closure_kinds.insert(def_id, kind);
+ kind
+ }
+
+ pub fn closure_type(this: &RefCell<Self>,
+ tcx: &ty::ctxt<'tcx>,
+ def_id: DefId,
+ substs: &ClosureSubsts<'tcx>)
+ -> ty::ClosureTy<'tcx>
+ {
+ // If this is a local def-id, it should be inserted into the
+ // tables by typeck; else, it will be retreived from
+ // the external crate metadata.
+ if let Some(ty) = this.borrow().closure_tys.get(&def_id) {
+ return ty.subst(tcx, &substs.func_substs);
+ }
+
+ let ty = csearch::closure_ty(tcx, def_id);
+ this.borrow_mut().closure_tys.insert(def_id, ty.clone());
+ ty.subst(tcx, &substs.func_substs)
+ }
}
impl<'tcx> CommonTypes<'tcx> {
bool: mk(TyBool),
char: mk(TyChar),
err: mk(TyError),
- isize: mk(TyInt(hir::TyIs)),
- i8: mk(TyInt(hir::TyI8)),
- i16: mk(TyInt(hir::TyI16)),
- i32: mk(TyInt(hir::TyI32)),
- i64: mk(TyInt(hir::TyI64)),
- usize: mk(TyUint(hir::TyUs)),
- u8: mk(TyUint(hir::TyU8)),
- u16: mk(TyUint(hir::TyU16)),
- u32: mk(TyUint(hir::TyU32)),
- u64: mk(TyUint(hir::TyU64)),
- f32: mk(TyFloat(hir::TyF32)),
- f64: mk(TyFloat(hir::TyF64)),
+ isize: mk(TyInt(ast::TyIs)),
+ i8: mk(TyInt(ast::TyI8)),
+ i16: mk(TyInt(ast::TyI16)),
+ i32: mk(TyInt(ast::TyI32)),
+ i64: mk(TyInt(ast::TyI64)),
+ usize: mk(TyUint(ast::TyUs)),
+ u8: mk(TyUint(ast::TyU8)),
+ u16: mk(TyUint(ast::TyU16)),
+ u32: mk(TyUint(ast::TyU32)),
+ u64: mk(TyUint(ast::TyU64)),
+ f32: mk(TyFloat(ast::TyF32)),
+ f64: mk(TyFloat(ast::TyF64)),
}
}
}
/// Common types, pre-interned for your convenience.
pub types: CommonTypes<'tcx>,
- pub sess: Session,
+ pub sess: &'tcx Session,
pub def_map: DefMap,
pub named_region_map: resolve_lifetime::NamedRegionMap,
pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
pub normalized_cache: RefCell<FnvHashMap<Ty<'tcx>, Ty<'tcx>>>,
pub lang_items: middle::lang_items::LanguageItems,
- /// A mapping of fake provided method def_ids to the default implementation
- pub provided_method_sources: RefCell<DefIdMap<DefId>>,
/// Maps from def-id of a type or region parameter to its
/// (inferred) variance.
/// These caches are used by const_eval when decoding external constants.
pub extern_const_statics: RefCell<DefIdMap<NodeId>>,
- pub extern_const_variants: RefCell<DefIdMap<NodeId>>,
pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
pub node_lint_levels: RefCell<FnvHashMap<(NodeId, lint::LintId),
/// constitute it.
pub fragment_infos: RefCell<DefIdMap<Vec<ty::FragmentInfo>>>,
}
-impl<'tcx> ctxt<'tcx> {
- pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
- *self.tables.borrow().closure_kinds.get(&def_id).unwrap()
- }
-
- pub fn closure_type(&self,
- def_id: DefId,
- substs: &ClosureSubsts<'tcx>)
- -> ty::ClosureTy<'tcx>
- {
- self.tables.borrow().closure_tys.get(&def_id).unwrap().subst(self, &substs.func_substs)
- }
+impl<'tcx> ctxt<'tcx> {
pub fn type_parameter_def(&self,
node_id: NodeId)
-> ty::TypeParameterDef<'tcx>
/// to the context. The closure enforces that the type context and any interned
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
/// reference to the context, to allow formatting values that need it.
- pub fn create_and_enter<F, R>(s: Session,
+ pub fn create_and_enter<F, R>(s: &'tcx Session,
arenas: &'tcx CtxtArenas<'tcx>,
def_map: DefMap,
named_region_map: resolve_lifetime::NamedRegionMap,
region_maps: RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index<'tcx>,
- f: F) -> (Session, R)
+ f: F) -> R
where F: FnOnce(&ctxt<'tcx>) -> R
{
let interner = RefCell::new(FnvHashMap());
ty_param_defs: RefCell::new(NodeMap()),
normalized_cache: RefCell::new(FnvHashMap()),
lang_items: lang_items,
- provided_method_sources: RefCell::new(DefIdMap()),
inherent_impls: RefCell::new(DefIdMap()),
impl_items: RefCell::new(DefIdMap()),
used_unsafe: RefCell::new(NodeSet()),
populated_external_types: RefCell::new(DefIdSet()),
populated_external_primitive_impls: RefCell::new(DefIdSet()),
extern_const_statics: RefCell::new(DefIdMap()),
- extern_const_variants: RefCell::new(DefIdMap()),
extern_const_fns: RefCell::new(DefIdMap()),
node_lint_levels: RefCell::new(FnvHashMap()),
transmute_restrictions: RefCell::new(Vec::new()),
pub mod tls {
use middle::ty;
- use session::Session;
use std::fmt;
use syntax::codemap;
})
}
- pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F)
- -> (Session, R) {
- let result = codemap::SPAN_DEBUG.with(|span_dbg| {
+ pub fn enter<'tcx, F: FnOnce(&ty::ctxt<'tcx>) -> R, R>(tcx: ty::ctxt<'tcx>, f: F) -> R {
+ codemap::SPAN_DEBUG.with(|span_dbg| {
let original_span_debug = span_dbg.get();
span_dbg.set(span_debug);
let tls_ptr = &tcx as *const _ as *const ThreadLocalTyCx;
let result = TLS_TCX.set(unsafe { &*tls_ptr }, || f(&tcx));
span_dbg.set(original_span_debug);
result
- });
- (tcx.sess, result)
+ })
}
pub fn with<F: FnOnce(&ty::ctxt) -> R, R>(f: F) -> R {
ctxt::intern_ty(&self.arenas.type_, &self.interner, st)
}
- pub fn mk_mach_int(&self, tm: hir::IntTy) -> Ty<'tcx> {
+ pub fn mk_mach_int(&self, tm: ast::IntTy) -> Ty<'tcx> {
match tm {
- hir::TyIs => self.types.isize,
- hir::TyI8 => self.types.i8,
- hir::TyI16 => self.types.i16,
- hir::TyI32 => self.types.i32,
- hir::TyI64 => self.types.i64,
+ ast::TyIs => self.types.isize,
+ ast::TyI8 => self.types.i8,
+ ast::TyI16 => self.types.i16,
+ ast::TyI32 => self.types.i32,
+ ast::TyI64 => self.types.i64,
}
}
- pub fn mk_mach_uint(&self, tm: hir::UintTy) -> Ty<'tcx> {
+ pub fn mk_mach_uint(&self, tm: ast::UintTy) -> Ty<'tcx> {
match tm {
- hir::TyUs => self.types.usize,
- hir::TyU8 => self.types.u8,
- hir::TyU16 => self.types.u16,
- hir::TyU32 => self.types.u32,
- hir::TyU64 => self.types.u64,
+ ast::TyUs => self.types.usize,
+ ast::TyU8 => self.types.u8,
+ ast::TyU16 => self.types.u16,
+ ast::TyU32 => self.types.u32,
+ ast::TyU64 => self.types.u64,
}
}
- pub fn mk_mach_float(&self, tm: hir::FloatTy) -> Ty<'tcx> {
+ pub fn mk_mach_float(&self, tm: ast::FloatTy) -> Ty<'tcx> {
match tm {
- hir::TyF32 => self.types.f32,
- hir::TyF64 => self.types.f64,
+ ast::TyF32 => self.types.f32,
+ ast::TyF64 => self.types.f64,
}
}
use std::fmt;
use syntax::abi;
-use syntax::ast::Name;
+use syntax::ast::{self, Name};
use syntax::codemap::Span;
use rustc_front::hir;
Sorts(ExpectedFound<Ty<'tcx>>),
IntegerAsChar,
IntMismatch(ExpectedFound<ty::IntVarValue>),
- FloatMismatch(ExpectedFound<hir::FloatTy>),
+ FloatMismatch(ExpectedFound<ast::FloatTy>),
Traits(ExpectedFound<DefId>),
BuiltinBoundsMismatch(ExpectedFound<ty::BuiltinBounds>),
VariadicMismatch(ExpectedFound<bool>),
expected.ty,
found.ty));
- match (expected.def_id.is_local(),
- self.map.opt_span(expected.def_id.node)) {
- (true, Some(span)) => {
+ match
+ self.map.as_local_node_id(expected.def_id)
+ .and_then(|node_id| self.map.opt_span(node_id))
+ {
+ Some(span) => {
self.sess.span_note(span,
&format!("a default was defined here..."));
}
- (_, _) => {
+ None => {
self.sess.note(
&format!("a default is defined on `{}`",
self.item_path_str(expected.def_id)));
expected.origin_span,
&format!("...that was applied to an unconstrained type variable here"));
- match (found.def_id.is_local(),
- self.map.opt_span(found.def_id.node)) {
- (true, Some(span)) => {
+ match
+ self.map.as_local_node_id(found.def_id)
+ .and_then(|node_id| self.map.opt_span(node_id))
+ {
+ Some(span) => {
self.sess.span_note(span,
&format!("a second default was defined here..."));
}
- (_, _) => {
+ None => {
self.sess.note(
&format!("a second default is defined on `{}`",
self.item_path_str(found.def_id)));
use middle::def_id::DefId;
use middle::ty::{self, Ty};
-use rustc_front::hir;
+use syntax::ast;
use self::SimplifiedType::*;
pub enum SimplifiedType {
BoolSimplifiedType,
CharSimplifiedType,
- IntSimplifiedType(hir::IntTy),
- UintSimplifiedType(hir::UintTy),
- FloatSimplifiedType(hir::FloatTy),
+ IntSimplifiedType(ast::IntTy),
+ UintSimplifiedType(ast::UintTy),
+ FloatSimplifiedType(ast::FloatTy),
EnumSimplifiedType(DefId),
StrSimplifiedType,
VecSimplifiedType,
use front::map as ast_map;
use front::map::LinkedPath;
use metadata::csearch;
+use metadata::cstore::LOCAL_CRATE;
use middle;
use middle::def::{self, ExportMap};
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace};
use middle::traits;
use std::vec::IntoIter;
use std::collections::{HashMap, HashSet};
use syntax::ast::{self, CrateNum, Name, NodeId};
+use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::Span;
use syntax::parse::token::{InternedString, special_idents};
use rustc_front::hir;
use rustc_front::hir::{ItemImpl, ItemTrait};
use rustc_front::hir::{MutImmutable, MutMutable, Visibility};
-use rustc_front::attr::{self, AttrMetaMethods};
pub use self::sty::{Binder, DebruijnIndex};
pub use self::sty::{BuiltinBound, BuiltinBounds, ExistentialBounds};
/// The complete set of all analyses described in this module. This is
/// produced by the driver and fed to trans and later passes.
-pub struct CrateAnalysis {
+pub struct CrateAnalysis<'a> {
pub export_map: ExportMap,
pub exported_items: middle::privacy::ExportedItems,
pub public_items: middle::privacy::PublicItems,
pub reachable: NodeSet,
- pub name: String,
+ pub name: &'a str,
pub glob_map: Option<GlobMap>,
}
pub vis: hir::Visibility,
pub def_id: DefId,
pub container: ImplOrTraitItemContainer,
-
- // If this method is provided, we need to know where it came from
- pub provided_source: Option<DefId>
}
impl<'tcx> Method<'tcx> {
explicit_self: ExplicitSelfCategory,
vis: hir::Visibility,
def_id: DefId,
- container: ImplOrTraitItemContainer,
- provided_source: Option<DefId>)
+ container: ImplOrTraitItemContainer)
-> Method<'tcx> {
Method {
name: name,
vis: vis,
def_id: def_id,
container: container,
- provided_source: provided_source
}
}
pub vis: hir::Visibility,
pub def_id: DefId,
pub container: ImplOrTraitItemContainer,
- pub default: Option<DefId>,
+ pub has_value: bool
}
#[derive(Clone, Copy, Debug)]
pub struct CReaderCacheKey {
pub cnum: CrateNum,
pub pos: usize,
- pub len: usize
}
/// A restriction that certain types must be the same size. The use of
#[derive(Clone, Copy, PartialEq)]
pub enum IntVarValue {
- IntType(hir::IntTy),
- UintType(hir::UintTy),
+ IntType(ast::IntTy),
+ UintType(ast::UintTy),
}
/// Default region to use for the bound of objects that are
impl RegionParameterDef {
pub fn to_early_bound_region(&self) -> ty::Region {
ty::ReEarlyBound(ty::EarlyBoundRegion {
- param_id: self.def_id.node,
+ def_id: self.def_id,
space: self.space,
index: self.index,
name: self.name,
// associated types don't have their own entry (for some reason),
// so for now just grab environment for the impl
let impl_id = cx.map.get_parent(id);
- let impl_def_id = DefId::local(impl_id);
+ let impl_def_id = cx.map.local_def_id(impl_id);
let scheme = cx.lookup_item_type(impl_def_id);
let predicates = cx.lookup_predicates(impl_def_id);
cx.construct_parameter_environment(impl_item.span,
id)
}
hir::ConstImplItem(_, _) => {
- let def_id = DefId::local(id);
+ let def_id = cx.map.local_def_id(id);
let scheme = cx.lookup_item_type(def_id);
let predicates = cx.lookup_predicates(def_id);
cx.construct_parameter_environment(impl_item.span,
id)
}
hir::MethodImplItem(_, ref body) => {
- let method_def_id = DefId::local(id);
+ let method_def_id = cx.map.local_def_id(id);
match cx.impl_or_trait_item(method_def_id) {
MethodTraitItem(ref method_ty) => {
let method_generics = &method_ty.generics;
// associated types don't have their own entry (for some reason),
// so for now just grab environment for the trait
let trait_id = cx.map.get_parent(id);
- let trait_def_id = DefId::local(trait_id);
+ let trait_def_id = cx.map.local_def_id(trait_id);
let trait_def = cx.lookup_trait_def(trait_def_id);
let predicates = cx.lookup_predicates(trait_def_id);
cx.construct_parameter_environment(trait_item.span,
id)
}
hir::ConstTraitItem(..) => {
- let def_id = DefId::local(id);
+ let def_id = cx.map.local_def_id(id);
let scheme = cx.lookup_item_type(def_id);
let predicates = cx.lookup_predicates(def_id);
cx.construct_parameter_environment(trait_item.span,
// block, unless this is a trait method with
// no default, then fallback to the method id.
let body_id = body.as_ref().map(|b| b.id).unwrap_or(id);
- let method_def_id = DefId::local(id);
-
+ let method_def_id = cx.map.local_def_id(id);
match cx.impl_or_trait_item(method_def_id) {
MethodTraitItem(ref method_ty) => {
let method_generics = &method_ty.generics;
match item.node {
hir::ItemFn(_, _, _, _, _, ref body) => {
// We assume this is a function.
- let fn_def_id = DefId::local(id);
+ let fn_def_id = cx.map.local_def_id(id);
let fn_scheme = cx.lookup_item_type(fn_def_id);
let fn_predicates = cx.lookup_predicates(fn_def_id);
hir::ItemImpl(..) |
hir::ItemConst(..) |
hir::ItemStatic(..) => {
- let def_id = DefId::local(id);
+ let def_id = cx.map.local_def_id(id);
let scheme = cx.lookup_item_type(def_id);
let predicates = cx.lookup_predicates(def_id);
cx.construct_parameter_environment(item.span,
id)
}
hir::ItemTrait(..) => {
- let def_id = DefId::local(id);
+ let def_id = cx.map.local_def_id(id);
let trait_def = cx.lookup_trait_def(def_id);
let predicates = cx.lookup_predicates(def_id);
cx.construct_parameter_environment(item.span,
pub type FieldDefMaster<'tcx> = &'tcx FieldDefData<'tcx, 'tcx>;
pub struct VariantDefData<'tcx, 'container: 'tcx> {
+ /// The variant's DefId. If this is a tuple-like struct,
+ /// this is the DefId of the struct's ctor.
pub did: DefId,
pub name: Name, // struct's name if this is a struct
pub disr_val: Disr,
- pub fields: Vec<FieldDefData<'tcx, 'container>>
+ pub fields: Vec<FieldDefData<'tcx, 'container>>,
}
pub struct FieldDefData<'tcx, 'container: 'tcx> {
pub enum AdtKind { Struct, Enum }
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub enum VariantKind { Dict, Tuple, Unit }
+pub enum VariantKind { Struct, Tuple, Unit }
impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
fn new(tcx: &ctxt<'tcx>,
Some(&FieldDefData { name, .. }) if name == special_idents::unnamed_field.name => {
VariantKind::Tuple
}
- Some(_) => VariantKind::Dict
+ Some(_) => VariantKind::Struct
}
}
hir::ExprCast(..) => {
false
}
-
- hir::ExprParen(ref e) => self.expr_is_lval(e),
}
}
- pub fn provided_source(&self, id: DefId) -> Option<DefId> {
- self.provided_method_sources.borrow().get(&id).cloned()
- }
-
pub fn provided_trait_methods(&self, id: DefId) -> Vec<Rc<Method<'tcx>>> {
- if id.is_local() {
- if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id.node).node {
+ if let Some(id) = self.map.as_local_node_id(id) {
+ if let ItemTrait(_, _, _, ref ms) = self.map.expect_item(id).node {
ms.iter().filter_map(|ti| {
if let hir::MethodTraitItem(_, Some(_)) = ti.node {
- match self.impl_or_trait_item(DefId::local(ti.id)) {
+ match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
MethodTraitItem(m) => Some(m),
_ => {
self.sess.bug("provided_trait_methods(): \
}
pub fn associated_consts(&self, id: DefId) -> Vec<Rc<AssociatedConst<'tcx>>> {
- if id.is_local() {
- match self.map.expect_item(id.node).node {
+ if let Some(id) = self.map.as_local_node_id(id) {
+ match self.map.expect_item(id).node {
ItemTrait(_, _, _, ref tis) => {
tis.iter().filter_map(|ti| {
if let hir::ConstTraitItem(_, _) = ti.node {
- match self.impl_or_trait_item(DefId::local(ti.id)) {
+ match self.impl_or_trait_item(self.map.local_def_id(ti.id)) {
ConstTraitItem(ac) => Some(ac),
_ => {
self.sess.bug("associated_consts(): \
ItemImpl(_, _, _, _, _, ref iis) => {
iis.iter().filter_map(|ii| {
if let hir::ConstImplItem(_, _) = ii.node {
- match self.impl_or_trait_item(DefId::local(ii.id)) {
+ match self.impl_or_trait_item(self.map.local_def_id(ii.id)) {
ConstTraitItem(ac) => Some(ac),
_ => {
self.sess.bug("associated_consts(): \
}
pub fn trait_impl_polarity(&self, id: DefId) -> Option<hir::ImplPolarity> {
- if id.is_local() {
- match self.map.find(id.node) {
+ if let Some(id) = self.map.as_local_node_id(id) {
+ match self.map.find(id) {
Some(ast_map::NodeItem(item)) => {
match item.node {
hir::ItemImpl(_, polarity, _, _, _, _) => Some(polarity),
/// Returns whether this DefId refers to an impl
pub fn is_impl(&self, id: DefId) -> bool {
- if id.is_local() {
+ if let Some(id) = self.map.as_local_node_id(id) {
if let Some(ast_map::NodeItem(
- &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id.node) {
+ &hir::Item { node: hir::ItemImpl(..), .. })) = self.map.find(id) {
true
} else {
false
self.with_path(id, |path| ast_map::path_to_string(path))
}
+ pub fn def_path(&self, id: DefId) -> ast_map::DefPath {
+ if id.is_local() {
+ self.map.def_path(id)
+ } else {
+ csearch::def_path(self, id)
+ }
+ }
+
pub fn with_path<T, F>(&self, id: DefId, f: F) -> T where
F: FnOnce(ast_map::PathElems) -> T,
{
- if id.is_local() {
- self.map.with_path(id.node, f)
+ if let Some(id) = self.map.as_local_node_id(id) {
+ self.map.with_path(id, f)
} else {
f(csearch::get_item_path(self, id).iter().cloned().chain(LinkedPath::empty()))
}
}
pub fn item_name(&self, id: DefId) -> ast::Name {
- if id.is_local() {
- self.map.get_path_elem(id.node).name()
+ if let Some(id) = self.map.as_local_node_id(id) {
+ self.map.get_path_elem(id).name()
} else {
csearch::get_item_name(self, id)
}
}
/// Get the attributes of a definition.
- pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [hir::Attribute]> {
- if did.is_local() {
- Cow::Borrowed(self.map.attrs(did.node))
+ pub fn get_attrs(&self, did: DefId) -> Cow<'tcx, [ast::Attribute]> {
+ if let Some(id) = self.map.as_local_node_id(did) {
+ Cow::Borrowed(self.map.attrs(id))
} else {
Cow::Owned(csearch::get_item_attrs(&self.sess.cstore, did))
}
// the map. This is a bit unfortunate.
for impl_item_def_id in &impl_items {
let method_def_id = impl_item_def_id.def_id();
- match self.impl_or_trait_item(method_def_id) {
- MethodTraitItem(method) => {
- if let Some(source) = method.provided_source {
- self.provided_method_sources
- .borrow_mut()
- .insert(method_def_id, source);
- }
- }
- _ => {}
- }
+ // load impl items eagerly for convenience
+ // FIXME: we may want to load these lazily
+ self.impl_or_trait_item(method_def_id);
}
// Store the implementation info.
def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID);
}
+ pub fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind {
+ Tables::closure_kind(&self.tables, self, def_id)
+ }
+
+ pub fn closure_type(&self,
+ def_id: DefId,
+ substs: &ClosureSubsts<'tcx>)
+ -> ty::ClosureTy<'tcx>
+ {
+ Tables::closure_type(&self.tables, self, def_id, substs)
+ }
+
/// Given the def_id of an impl, return the def_id of the trait it implements.
/// If it implements no trait, return `None`.
pub fn trait_id_of_impl(&self, def_id: DefId) -> Option<DefId> {
impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for [T] {
type Lifted = Vec<T::Lifted>;
fn lift_to_tcx(&self, tcx: &ty::ctxt<'tcx>) -> Option<Self::Lifted> {
- let mut result = Vec::with_capacity(self.len());
+ // type annotation needed to inform `projection_must_outlive`
+ let mut result : Vec<<T as Lift<'tcx>>::Lifted>
+ = Vec::with_capacity(self.len());
for x in self {
if let Some(value) = tcx.lift(x) {
result.push(value);
use std::ops;
use std::mem;
use syntax::abi;
-use syntax::ast::{Name, NodeId};
+use syntax::ast::{self, Name};
use syntax::parse::token::special_idents;
use rustc_front::hir;
TyChar,
/// A primitive signed integer type. For example, `i32`.
- TyInt(hir::IntTy),
+ TyInt(ast::IntTy),
/// A primitive unsigned integer type. For example, `u32`.
- TyUint(hir::UintTy),
+ TyUint(ast::UintTy),
/// A primitive floating-point type. For example, `f64`.
- TyFloat(hir::FloatTy),
+ TyFloat(ast::FloatTy),
/// An enumerated type, defined with `enum`.
///
/// That is, even after substitution it is possible that there are type
/// variables. This happens when the `TyEnum` corresponds to an enum
/// definition and not a concrete use of it. To get the correct `TyEnum`
- /// from the tcx, use the `NodeId` from the `hir::Ty` and look it up in
+ /// from the tcx, use the `NodeId` from the `ast::Ty` and look it up in
/// the `ast_ty_to_ty_cache`. This is probably true for `TyStruct` as
/// well.
TyEnum(AdtDef<'tcx>, &'tcx Substs<'tcx>),
TyRef(&'tcx Region, TypeAndMut<'tcx>),
/// If the def-id is Some(_), then this is the type of a specific
- /// fn item. Otherwise, if None(_), it a fn pointer type.
+ /// fn item. Otherwise, if None(_), it is a fn pointer type.
///
/// FIXME: Conflating function pointers and the type of a
/// function is probably a terrible idea; a function pointer is a
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub struct EarlyBoundRegion {
- pub param_id: NodeId,
+ pub def_id: DefId,
pub space: subst::ParamSpace,
pub index: u32,
pub name: Name,
}
}
+ pub fn is_phantom_data(&self) -> bool {
+ if let TyStruct(def, _) = self.sty {
+ def.is_phantom_data()
+ } else {
+ false
+ }
+ }
+
pub fn is_bool(&self) -> bool { self.sty == TyBool }
pub fn is_param(&self, space: subst::ParamSpace, index: u32) -> bool {
pub fn sequence_element_type(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
match self.sty {
TyArray(ty, _) | TySlice(ty) => ty,
- TyStr => cx.mk_mach_uint(hir::TyU8),
+ TyStr => cx.mk_mach_uint(ast::TyU8),
_ => cx.sess.bug(&format!("sequence_element_type called on non-sequence value: {}",
self)),
}
pub fn is_uint(&self) -> bool {
match self.sty {
- TyInfer(IntVar(_)) | TyUint(hir::TyUs) => true,
+ TyInfer(IntVar(_)) | TyUint(ast::TyUs) => true,
_ => false
}
}
pub fn is_machine(&self) -> bool {
match self.sty {
- TyInt(hir::TyIs) | TyUint(hir::TyUs) => false,
+ TyInt(ast::TyIs) | TyUint(ast::TyUs) => false,
TyInt(..) | TyUint(..) | TyFloat(..) => true,
_ => false
}
use middle::const_eval::{self, ConstVal, ErrKind};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def_id::DefId;
-use middle::subst;
+use middle::subst::{self, Subst, Substs};
use middle::infer;
use middle::pat_util;
use middle::traits;
use std::cmp;
use std::hash::{Hash, SipHasher, Hasher};
-use syntax::ast::Name;
+use std::rc::Rc;
+use syntax::ast::{self, Name};
+use syntax::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
use syntax::codemap::Span;
use rustc_front::hir;
-use rustc_front::attr::{self, AttrMetaMethods, SignedInt, UnsignedInt};
pub trait IntTypeExt {
fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx>;
impl IntTypeExt for attr::IntType {
fn to_ty<'tcx>(&self, cx: &ty::ctxt<'tcx>) -> Ty<'tcx> {
match *self {
- SignedInt(hir::TyI8) => cx.types.i8,
- SignedInt(hir::TyI16) => cx.types.i16,
- SignedInt(hir::TyI32) => cx.types.i32,
- SignedInt(hir::TyI64) => cx.types.i64,
- SignedInt(hir::TyIs) => cx.types.isize,
- UnsignedInt(hir::TyU8) => cx.types.u8,
- UnsignedInt(hir::TyU16) => cx.types.u16,
- UnsignedInt(hir::TyU32) => cx.types.u32,
- UnsignedInt(hir::TyU64) => cx.types.u64,
- UnsignedInt(hir::TyUs) => cx.types.usize,
+ SignedInt(ast::TyI8) => cx.types.i8,
+ SignedInt(ast::TyI16) => cx.types.i16,
+ SignedInt(ast::TyI32) => cx.types.i32,
+ SignedInt(ast::TyI64) => cx.types.i64,
+ SignedInt(ast::TyIs) => cx.types.isize,
+ UnsignedInt(ast::TyU8) => cx.types.u8,
+ UnsignedInt(ast::TyU16) => cx.types.u16,
+ UnsignedInt(ast::TyU32) => cx.types.u32,
+ UnsignedInt(ast::TyU64) => cx.types.u64,
+ UnsignedInt(ast::TyUs) => cx.types.usize,
}
}
fn i64_to_disr(&self, val: i64) -> Option<Disr> {
match *self {
- SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr),
- SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr),
- SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr),
- SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr),
- UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr),
- UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr),
- UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr),
- UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr),
-
- UnsignedInt(hir::TyUs) |
- SignedInt(hir::TyIs) => unreachable!(),
+ SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr),
+ SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr),
+ SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr),
+ SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
}
}
fn u64_to_disr(&self, val: u64) -> Option<Disr> {
match *self {
- SignedInt(hir::TyI8) => val.to_i8() .map(|v| v as Disr),
- SignedInt(hir::TyI16) => val.to_i16() .map(|v| v as Disr),
- SignedInt(hir::TyI32) => val.to_i32() .map(|v| v as Disr),
- SignedInt(hir::TyI64) => val.to_i64() .map(|v| v as Disr),
- UnsignedInt(hir::TyU8) => val.to_u8() .map(|v| v as Disr),
- UnsignedInt(hir::TyU16) => val.to_u16() .map(|v| v as Disr),
- UnsignedInt(hir::TyU32) => val.to_u32() .map(|v| v as Disr),
- UnsignedInt(hir::TyU64) => val.to_u64() .map(|v| v as Disr),
-
- UnsignedInt(hir::TyUs) |
- SignedInt(hir::TyIs) => unreachable!(),
+ SignedInt(ast::TyI8) => val.to_i8() .map(|v| v as Disr),
+ SignedInt(ast::TyI16) => val.to_i16() .map(|v| v as Disr),
+ SignedInt(ast::TyI32) => val.to_i32() .map(|v| v as Disr),
+ SignedInt(ast::TyI64) => val.to_i64() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU8) => val.to_u8() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU16) => val.to_u16() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU32) => val.to_u32() .map(|v| v as Disr),
+ UnsignedInt(ast::TyU64) => val.to_u64() .map(|v| v as Disr),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
}
}
// SignedInt repr means we *want* to reinterpret the bits
// treating the highest bit of Disr as a sign-bit, so
// cast to i64 before range-checking.
- SignedInt(hir::TyI8) => add1!((val as i64).to_i8()),
- SignedInt(hir::TyI16) => add1!((val as i64).to_i16()),
- SignedInt(hir::TyI32) => add1!((val as i64).to_i32()),
- SignedInt(hir::TyI64) => add1!(Some(val as i64)),
-
- UnsignedInt(hir::TyU8) => add1!(val.to_u8()),
- UnsignedInt(hir::TyU16) => add1!(val.to_u16()),
- UnsignedInt(hir::TyU32) => add1!(val.to_u32()),
- UnsignedInt(hir::TyU64) => add1!(Some(val)),
-
- UnsignedInt(hir::TyUs) |
- SignedInt(hir::TyIs) => unreachable!(),
+ SignedInt(ast::TyI8) => add1!((val as i64).to_i8()),
+ SignedInt(ast::TyI16) => add1!((val as i64).to_i16()),
+ SignedInt(ast::TyI32) => add1!((val as i64).to_i32()),
+ SignedInt(ast::TyI64) => add1!(Some(val as i64)),
+
+ UnsignedInt(ast::TyU8) => add1!(val.to_u8()),
+ UnsignedInt(ast::TyU16) => add1!(val.to_u16()),
+ UnsignedInt(ast::TyU32) => add1!(val.to_u32()),
+ UnsignedInt(ast::TyU64) => add1!(Some(val)),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
}
}
// full range from `i64::MIN` through `u64::MAX`.
fn disr_string(&self, val: Disr) -> String {
match *self {
- SignedInt(hir::TyI8) => format!("{}", val as i8 ),
- SignedInt(hir::TyI16) => format!("{}", val as i16),
- SignedInt(hir::TyI32) => format!("{}", val as i32),
- SignedInt(hir::TyI64) => format!("{}", val as i64),
- UnsignedInt(hir::TyU8) => format!("{}", val as u8 ),
- UnsignedInt(hir::TyU16) => format!("{}", val as u16),
- UnsignedInt(hir::TyU32) => format!("{}", val as u32),
- UnsignedInt(hir::TyU64) => format!("{}", val as u64),
-
- UnsignedInt(hir::TyUs) |
- SignedInt(hir::TyIs) => unreachable!(),
+ SignedInt(ast::TyI8) => format!("{}", val as i8 ),
+ SignedInt(ast::TyI16) => format!("{}", val as i16),
+ SignedInt(ast::TyI32) => format!("{}", val as i32),
+ SignedInt(ast::TyI64) => format!("{}", val as i64),
+ UnsignedInt(ast::TyU8) => format!("{}", val as u8 ),
+ UnsignedInt(ast::TyU16) => format!("{}", val as u16),
+ UnsignedInt(ast::TyU32) => format!("{}", val as u32),
+ UnsignedInt(ast::TyU64) => format!("{}", val as u64),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
}
}
}
let val = val.unwrap_or(ty::INITIAL_DISCRIMINANT_VALUE);
match *self {
- SignedInt(hir::TyI8) => add1!(val as i8 ),
- SignedInt(hir::TyI16) => add1!(val as i16),
- SignedInt(hir::TyI32) => add1!(val as i32),
- SignedInt(hir::TyI64) => add1!(val as i64),
- UnsignedInt(hir::TyU8) => add1!(val as u8 ),
- UnsignedInt(hir::TyU16) => add1!(val as u16),
- UnsignedInt(hir::TyU32) => add1!(val as u32),
- UnsignedInt(hir::TyU64) => add1!(val as u64),
-
- UnsignedInt(hir::TyUs) |
- SignedInt(hir::TyIs) => unreachable!(),
+ SignedInt(ast::TyI8) => add1!(val as i8 ),
+ SignedInt(ast::TyI16) => add1!(val as i16),
+ SignedInt(ast::TyI32) => add1!(val as i32),
+ SignedInt(ast::TyI64) => add1!(val as i64),
+ UnsignedInt(ast::TyU8) => add1!(val as u8 ),
+ UnsignedInt(ast::TyU16) => add1!(val as u16),
+ UnsignedInt(ast::TyU32) => add1!(val as u32),
+ UnsignedInt(ast::TyU64) => add1!(val as u64),
+
+ UnsignedInt(ast::TyUs) |
+ SignedInt(ast::TyIs) => unreachable!(),
}
}
}
//
// NB. Historically `fn enum_variants` generate i64 here, while
// rustc_typeck::check would generate isize.
- _ => SignedInt(hir::TyIs),
+ _ => SignedInt(ast::TyIs),
};
let repr_type_ty = repr_type.to_ty(self);
let repr_type = match repr_type {
- SignedInt(hir::TyIs) =>
+ SignedInt(ast::TyIs) =>
SignedInt(self.sess.target.int_type),
- UnsignedInt(hir::TyUs) =>
+ UnsignedInt(ast::TyUs) =>
UnsignedInt(self.sess.target.uint_type),
other => other
};
/// Returns the repeat count for a repeating vector expression.
pub fn eval_repeat_count(&self, count_expr: &hir::Expr) -> usize {
let hint = UncheckedExprHint(self.types.usize);
- match const_eval::eval_const_expr_partial(self, count_expr, hint) {
+ match const_eval::eval_const_expr_partial(self, count_expr, hint, None) {
Ok(val) => {
let found = match val {
ConstVal::Uint(count) => return count as usize,
tcx.sess.cstore.get_crate_hash(did.krate)
};
h.as_str().hash(state);
- did.node.hash(state);
+ did.index.hash(state);
};
let mt = |state: &mut SipHasher, mt: TypeAndMut| {
mt.mutbl.hash(state);
}
}
- /// Returns true if this ADT is a dtorck type, i.e. whether it being
- /// safe for destruction requires it to be alive
+ /// Returns true if this ADT is a dtorck type.
+ ///
+ /// Invoking the destructor of a dtorck type during usual cleanup
+ /// (e.g. the glue emitted for stack unwinding) requires all
+ /// lifetimes in the type-structure of `adt` to strictly outlive
+ /// the adt value itself.
+ ///
+ /// If `adt` is not dtorck, then the adt's destructor can be
+ /// invoked even when there are lifetimes in the type-structure of
+ /// `adt` that do not strictly outlive the adt value itself.
+ /// (This allows programs to make cyclic structures without
+ /// resorting to unasfe means; see RFCs 769 and 1238).
pub fn is_adt_dtorck(&self, adt: ty::AdtDef<'tcx>) -> bool {
let dtor_method = match adt.destructor() {
Some(dtor) => dtor,
None => return false
};
- let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| {
- self.sess.bug(&format!("no Drop impl for the dtor of `{:?}`", adt))
- });
- let generics = adt.type_scheme(self).generics;
-
- // In `impl<'a> Drop ...`, we automatically assume
- // `'a` is meaningful and thus represents a bound
- // through which we could reach borrowed data.
+
+ // RFC 1238: if the destructor method is tagged with the
+ // attribute `unsafe_destructor_blind_to_params`, then the
+ // compiler is being instructed to *assume* that the
+ // destructor will not access borrowed data,
+ // even if such data is otherwise reachable.
//
- // FIXME (pnkfelix): In the future it would be good to
- // extend the language to allow the user to express,
- // in the impl signature, that a lifetime is not
- // actually used (something like `where 'a: ?Live`).
- if generics.has_region_params(subst::TypeSpace) {
- debug!("typ: {:?} has interesting dtor due to region params",
- adt);
- return true;
- }
+ // Such access can be in plain sight (e.g. dereferencing
+ // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
+ // (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
+ return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params");
+ }
+}
- let mut seen_items = Vec::new();
- let mut items_to_inspect = vec![impl_did];
- while let Some(item_def_id) = items_to_inspect.pop() {
- if seen_items.contains(&item_def_id) {
- continue;
- }
+#[derive(Debug)]
+pub struct ImplMethod<'tcx> {
+ pub method: Rc<ty::Method<'tcx>>,
+ pub substs: Substs<'tcx>,
+ pub is_provided: bool
+}
- for pred in self.lookup_predicates(item_def_id).predicates {
- let result = match pred {
- ty::Predicate::Equate(..) |
- ty::Predicate::RegionOutlives(..) |
- ty::Predicate::TypeOutlives(..) |
- ty::Predicate::WellFormed(..) |
- ty::Predicate::ObjectSafe(..) |
- ty::Predicate::Projection(..) => {
- // For now, assume all these where-clauses
- // may give drop implementation capabilty
- // to access borrowed data.
- true
+impl<'tcx> ty::ctxt<'tcx> {
+ #[inline(never)] // is this perfy enough?
+ pub fn get_impl_method(&self,
+ impl_def_id: DefId,
+ substs: Substs<'tcx>,
+ name: Name)
+ -> ImplMethod<'tcx>
+ {
+ // there don't seem to be nicer accessors to these:
+ let impl_or_trait_items_map = self.impl_or_trait_items.borrow();
+
+ for impl_item in &self.impl_items.borrow()[&impl_def_id] {
+ if let ty::MethodTraitItem(ref meth) =
+ impl_or_trait_items_map[&impl_item.def_id()] {
+ if meth.name == name {
+ return ImplMethod {
+ method: meth.clone(),
+ substs: substs,
+ is_provided: false
}
+ }
+ }
+ }
- ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
- let def_id = t_pred.trait_ref.def_id;
- if self.trait_items(def_id).len() != 0 {
- // If trait has items, assume it adds
- // capability to access borrowed data.
- true
- } else {
- // Trait without items is itself
- // uninteresting from POV of dropck.
- //
- // However, may have parent w/ items;
- // so schedule checking of predicates,
- items_to_inspect.push(def_id);
- // and say "no capability found" for now.
- false
- }
+ // It is not in the impl - get the default from the trait.
+ let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
+ for trait_item in self.trait_items(trait_ref.def_id).iter() {
+ if let &ty::MethodTraitItem(ref meth) = trait_item {
+ if meth.name == name {
+ let impl_to_trait_substs = self
+ .make_substs_for_receiver_types(&trait_ref, meth);
+ return ImplMethod {
+ method: meth.clone(),
+ substs: impl_to_trait_substs.subst(self, &substs),
+ is_provided: true
}
- };
-
- if result {
- debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}",
- adt, pred);
- return true;
}
}
-
- seen_items.push(item_def_id);
}
- debug!("typ: {:?} is dtorck-safe", adt);
- false
+ self.sess.bug(&format!("method {:?} not found in {:?}",
+ name, impl_def_id))
}
}
use metadata::csearch;
use middle::lang_items;
+use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
use rustc_front::visit::Visitor;
verify(sess, items);
}
-pub fn link_name(attrs: &[hir::Attribute]) -> Option<InternedString> {
+pub fn link_name(attrs: &[ast::Attribute]) -> Option<InternedString> {
lang_items::extract(attrs).and_then(|name| {
$(if &name[..] == stringify!($name) {
Some(InternedString::new(stringify!($sym)))
//! Used by `rustc` when compiling a plugin crate.
use syntax::ast;
+use syntax::attr;
use syntax::codemap::Span;
use syntax::diagnostic;
use rustc_front::visit;
use rustc_front::visit::Visitor;
use rustc_front::hir;
-use rustc_front::attr;
struct RegistrarFinder {
registrars: Vec<(ast::NodeId, Span)> ,
use plugin::registry::Registry;
use std::borrow::ToOwned;
-use std::dynamic_lib::DynamicLibrary;
use std::env;
use std::mem;
use std::path::PathBuf;
plugins: Vec<PluginRegistrar>,
}
+fn call_malformed_plugin_attribute(a: &Session, b: Span) {
+ span_err!(a, b, E0498, "malformed plugin attribute");
+}
+
/// Read plugin metadata and dynamically load registrar functions.
pub fn load_plugins(sess: &Session, krate: &ast::Crate,
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
let plugins = match attr.meta_item_list() {
Some(xs) => xs,
None => {
- sess.span_err(attr.span, "malformed plugin attribute");
+ call_malformed_plugin_attribute(sess, attr.span);
continue;
}
};
for plugin in plugins {
if plugin.value_str().is_some() {
- sess.span_err(attr.span, "malformed plugin attribute");
+ call_malformed_plugin_attribute(sess, attr.span);
continue;
}
}
// Dynamically link a registrar function into the compiler process.
+ #[allow(deprecated)]
fn dylink_registrar(&mut self,
span: Span,
path: PathBuf,
symbol: String) -> PluginRegistrarFun {
+ use std::dynamic_lib::DynamicLibrary;
+
// Make sure the path contains a / or the linker will search for it.
let path = env::current_dir().unwrap().join(&path);
//! Used by plugin crates to tell `rustc` about the plugins they provide.
-use lint::{LintPassObject, LintId, Lint};
+use lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
use session::Session;
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
pub syntax_exts: Vec<NamedSyntaxExtension>,
#[doc(hidden)]
- pub lint_passes: Vec<LintPassObject>,
+ pub early_lint_passes: Vec<EarlyLintPassObject>,
+
+ #[doc(hidden)]
+ pub late_lint_passes: Vec<LateLintPassObject>,
#[doc(hidden)]
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
args_hidden: None,
krate_span: krate.span,
syntax_exts: vec!(),
- lint_passes: vec!(),
+ early_lint_passes: vec!(),
+ late_lint_passes: vec!(),
lint_groups: HashMap::new(),
llvm_passes: vec!(),
attributes: vec!(),
/// Register a syntax extension of any kind.
///
/// This is the most general hook into `libsyntax`'s expansion behavior.
- #[allow(deprecated)]
pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
self.syntax_exts.push((name, match extension {
NormalTT(ext, _, allow_internal_unstable) => {
}
/// Register a compiler lint pass.
- pub fn register_lint_pass(&mut self, lint_pass: LintPassObject) {
- self.lint_passes.push(lint_pass);
+ pub fn register_early_lint_pass(&mut self, lint_pass: EarlyLintPassObject) {
+ self.early_lint_passes.push(lint_pass);
}
+ /// Register a compiler lint pass.
+ pub fn register_late_lint_pass(&mut self, lint_pass: LateLintPassObject) {
+ self.late_lint_passes.push(lint_pass);
+ }
/// Register a lint group.
pub fn register_lint_group(&mut self, name: &'static str, to: Vec<&'static Lint>) {
self.lint_groups.insert(name, to.into_iter().map(|x| LintId::of(x)).collect());
pub use self::CrateType::*;
pub use self::Passes::*;
pub use self::OptLevel::*;
-pub use self::OutputType::*;
pub use self::DebugInfoLevel::*;
use session::{early_error, early_warn, Session};
use lint;
use metadata::cstore;
-use syntax::ast;
-use rustc_front::hir::{IntTy, UintTy};
+use syntax::ast::{self, IntTy, UintTy};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
-use rustc_front::hir;
use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler};
use syntax::parse;
use syntax::parse::token::InternedString;
FullDebugInfo,
}
-#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum OutputType {
- OutputTypeBitcode,
- OutputTypeAssembly,
- OutputTypeLlvmAssembly,
- OutputTypeObject,
- OutputTypeExe,
- OutputTypeDepInfo,
+ Bitcode,
+ Assembly,
+ LlvmAssembly,
+ Object,
+ Exe,
+ DepInfo,
}
#[derive(Clone)]
pub lint_opts: Vec<(String, lint::Level)>,
pub lint_cap: Option<lint::Level>,
pub describe_lints: bool,
- pub output_types: Vec<OutputType>,
+ pub output_types: HashMap<OutputType, Option<PathBuf>>,
// This was mutable for rustpkg, which updates search paths based on the
// parsed code. It remains mutable in case its replacements wants to use
// this.
pub parse_only: bool,
pub no_trans: bool,
pub treat_err_as_bug: bool,
- pub always_build_mir: bool,
pub no_analysis: bool,
pub debugging_opts: DebuggingOptions,
- /// Whether to write dependency files. It's (enabled, optional filename).
- pub write_dependency_info: (bool, Option<PathBuf>),
pub prints: Vec<PrintRequest>,
pub cg: CodegenOptions,
pub color: ColorConfig,
pub out_filestem: String,
pub single_output_file: Option<PathBuf>,
pub extra: String,
+ pub outputs: HashMap<OutputType, Option<PathBuf>>,
}
impl OutputFilenames {
pub fn path(&self, flavor: OutputType) -> PathBuf {
- match self.single_output_file {
- Some(ref path) => return path.clone(),
- None => {}
- }
- self.temp_path(flavor)
+ self.outputs.get(&flavor).and_then(|p| p.to_owned())
+ .or_else(|| self.single_output_file.clone())
+ .unwrap_or_else(|| self.temp_path(flavor))
}
pub fn temp_path(&self, flavor: OutputType) -> PathBuf {
let base = self.out_directory.join(&self.filestem());
match flavor {
- OutputTypeBitcode => base.with_extension("bc"),
- OutputTypeAssembly => base.with_extension("s"),
- OutputTypeLlvmAssembly => base.with_extension("ll"),
- OutputTypeObject => base.with_extension("o"),
- OutputTypeDepInfo => base.with_extension("d"),
- OutputTypeExe => base,
+ OutputType::Bitcode => base.with_extension("bc"),
+ OutputType::Assembly => base.with_extension("s"),
+ OutputType::LlvmAssembly => base.with_extension("ll"),
+ OutputType::Object => base.with_extension("o"),
+ OutputType::DepInfo => base.with_extension("d"),
+ OutputType::Exe => base,
}
}
lint_opts: Vec::new(),
lint_cap: None,
describe_lints: false,
- output_types: Vec::new(),
+ output_types: HashMap::new(),
search_paths: SearchPaths::new(),
maybe_sysroot: None,
target_triple: host_triple().to_string(),
parse_only: false,
no_trans: false,
treat_err_as_bug: false,
- always_build_mir: false,
no_analysis: false,
debugging_opts: basic_debugging_options(),
- write_dependency_info: (false, None),
prints: Vec::new(),
cg: basic_codegen_options(),
color: Auto,
"Run all passes except translation; no output"),
treat_err_as_bug: bool = (false, parse_bool,
"Treat all errors that occur as bugs"),
- always_build_mir: bool = (false, parse_bool,
- "Always build MIR for all fns, even without a #[rustc_mir] annotation"),
no_analysis: bool = (false, parse_bool,
"Parse and expand the source, but run no analysis"),
extra_plugins: Vec<String> = (Vec::new(), parse_list,
"For every macro invocation, print its name and arguments"),
enable_nonzeroing_move_hints: bool = (false, parse_bool,
"Force nonzeroing move optimization on"),
+ keep_mtwt_tables: bool = (false, parse_bool,
+ "Don't clear the resolution tables after analysis"),
}
pub fn default_lib_output() -> CrateType {
let wordsz = &sess.target.target.target_pointer_width;
let os = &sess.target.target.target_os;
let env = &sess.target.target.target_env;
+ let vendor = &sess.target.target.target_vendor;
let fam = match sess.target.target.options.is_like_windows {
true => InternedString::new("windows"),
mk(InternedString::new("target_endian"), intern(end)),
mk(InternedString::new("target_pointer_width"), intern(wordsz)),
mk(InternedString::new("target_env"), intern(env)),
+ mk(InternedString::new("target_vendor"), intern(vendor)),
];
if sess.opts.debug_assertions {
ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
};
let (int_type, uint_type) = match &target.target_pointer_width[..] {
- "32" => (hir::TyI32, hir::TyU32),
- "64" => (hir::TyI64, hir::TyU64),
+ "32" => (ast::TyI32, ast::TyU32),
+ "64" => (ast::TyI64, ast::TyU64),
w => sp.handler().fatal(&format!("target specification was invalid: unrecognized \
target-pointer-width {}", w))
};
let parse_only = debugging_opts.parse_only;
let no_trans = debugging_opts.no_trans;
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
- let always_build_mir = debugging_opts.always_build_mir;
let no_analysis = debugging_opts.no_analysis;
if debugging_opts.debug_llvm {
unsafe { llvm::LLVMSetDebug(1); }
}
- let mut output_types = Vec::new();
+ let mut output_types = HashMap::new();
if !debugging_opts.parse_only && !no_trans {
- let unparsed_output_types = matches.opt_strs("emit");
- for unparsed_output_type in &unparsed_output_types {
- for part in unparsed_output_type.split(',') {
- let output_type = match part {
- "asm" => OutputTypeAssembly,
- "llvm-ir" => OutputTypeLlvmAssembly,
- "llvm-bc" => OutputTypeBitcode,
- "obj" => OutputTypeObject,
- "link" => OutputTypeExe,
- "dep-info" => OutputTypeDepInfo,
- _ => {
+ for list in matches.opt_strs("emit") {
+ for output_type in list.split(',') {
+ let mut parts = output_type.splitn(2, '=');
+ let output_type = match parts.next().unwrap() {
+ "asm" => OutputType::Assembly,
+ "llvm-ir" => OutputType::LlvmAssembly,
+ "llvm-bc" => OutputType::Bitcode,
+ "obj" => OutputType::Object,
+ "link" => OutputType::Exe,
+ "dep-info" => OutputType::DepInfo,
+ part => {
early_error(color, &format!("unknown emission type: `{}`",
part))
}
};
- output_types.push(output_type)
+ let path = parts.next().map(PathBuf::from);
+ output_types.insert(output_type, path);
}
}
};
- output_types.sort();
- output_types.dedup();
if output_types.is_empty() {
- output_types.push(OutputTypeExe);
+ output_types.insert(OutputType::Exe, None);
}
let cg = build_codegen_options(matches, color);
let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
let test = matches.opt_present("test");
- let write_dependency_info = (output_types.contains(&OutputTypeDepInfo), None);
let prints = matches.opt_strs("print").into_iter().map(|s| {
match &*s {
parse_only: parse_only,
no_trans: no_trans,
treat_err_as_bug: treat_err_as_bug,
- always_build_mir: always_build_mir,
no_analysis: no_analysis,
debugging_opts: debugging_opts,
- write_dependency_info: write_dependency_info,
prints: prints,
cg: cg,
color: color,
use session::search_paths::PathKind;
use util::nodemap::{NodeMap, FnvHashMap};
-use syntax::ast::NodeId;
+use syntax::ast::{NodeId, NodeIdAssigner};
use syntax::codemap::Span;
use syntax::diagnostic::{self, Emitter};
use syntax::diagnostics;
}
lints.insert(id, vec!((lint_id, sp, msg)));
}
- pub fn next_node_id(&self) -> ast::NodeId {
- self.reserve_node_ids(1)
- }
pub fn reserve_node_ids(&self, count: ast::NodeId) -> ast::NodeId {
let id = self.next_node_id.get();
}
}
+impl NodeIdAssigner for Session {
+ fn next_node_id(&self) -> NodeId {
+ self.reserve_node_ids(1)
+ }
+
+ fn peek_node_id(&self) -> NodeId {
+ self.next_node_id.get().checked_add(1).unwrap()
+ }
+}
+
fn split_msg_into_multilines(msg: &str) -> Option<String> {
// Conditions for enabling multi-line errors:
if !msg.contains("mismatched types") &&
let first = msg.match_indices("expected").filter(|s| {
s.0 > 0 && (msg.char_at_reverse(s.0) == ' ' ||
msg.char_at_reverse(s.0) == '(')
- }).map(|(a, b)| (a - 1, b));
+ }).map(|(a, b)| (a - 1, a + b.len()));
let second = msg.match_indices("found").filter(|s| {
msg.char_at_reverse(s.0) == ' '
- }).map(|(a, b)| (a - 1, b));
+ }).map(|(a, b)| (a - 1, a + b.len()));
let mut new_msg = String::new();
let mut head = 0;
use std::fmt;
use syntax::abi;
+use syntax::ast;
use syntax::parse::token;
-use syntax::ast::DUMMY_NODE_ID;
-use rustc_front::hir as ast;
+use syntax::ast::CRATE_NODE_ID;
+use rustc_front::hir;
pub fn verbose() -> bool {
ty::tls::with(|tcx| tcx.sess.verbose())
ty::BrEnv => {
let name = token::intern("'r");
let _ = write!(f, "{}", name);
- ty::BrNamed(DefId::local(DUMMY_NODE_ID), name)
+ ty::BrNamed(tcx.map.local_def_id(CRATE_NODE_ID), name)
}
})
}).0;
impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "TypeParameterDef({}, {}:{}, {:?}/{})",
+ write!(f, "TypeParameterDef({}, {:?}, {:?}/{})",
self.name,
- self.def_id.krate, self.def_id.node,
+ self.def_id,
self.space, self.index)
}
}
impl fmt::Debug for ty::RegionParameterDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "RegionParameterDef({}, {}:{}, {:?}/{}, {:?})",
+ write!(f, "RegionParameterDef({}, {:?}, {:?}/{}, {:?})",
self.name,
- self.def_id.krate, self.def_id.node,
+ self.def_id,
self.space, self.index,
self.bounds)
}
impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}{}",
- if self.mutbl == ast::MutMutable { "mut " } else { "" },
+ if self.mutbl == hir::MutMutable { "mut " } else { "" },
self.ty)
}
}
BrAnon(n) => write!(f, "BrAnon({:?})", n),
BrFresh(n) => write!(f, "BrFresh({:?})", n),
BrNamed(did, name) => {
- write!(f, "BrNamed({}:{}, {:?})", did.krate, did.node, name)
+ write!(f, "BrNamed({:?}, {:?})", did, name)
}
BrEnv => "BrEnv".fmt(f),
}
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ty::ReEarlyBound(ref data) => {
- write!(f, "ReEarlyBound({}, {:?}, {}, {})",
- data.param_id,
+ write!(f, "ReEarlyBound({:?}, {:?}, {}, {})",
+ data.def_id,
data.space,
data.index,
data.name)
TyBox(typ) => write!(f, "Box<{}>", typ),
TyRawPtr(ref tm) => {
write!(f, "*{} {}", match tm.mutbl {
- ast::MutMutable => "mut",
- ast::MutImmutable => "const",
+ hir::MutMutable => "mut",
+ hir::MutImmutable => "const",
}, tm.ty)
}
TyRef(r, ref tm) => {
write!(f, ")")
}
TyBareFn(opt_def_id, ref bare_fn) => {
- if bare_fn.unsafety == ast::Unsafety::Unsafe {
+ if bare_fn.unsafety == hir::Unsafety::Unsafe {
try!(write!(f, "unsafe "));
}
TyTrait(ref data) => write!(f, "{}", data),
ty::TyProjection(ref data) => write!(f, "{}", data),
TyStr => write!(f, "str"),
- TyClosure(ref did, ref substs) => ty::tls::with(|tcx| {
+ TyClosure(did, ref substs) => ty::tls::with(|tcx| {
try!(write!(f, "[closure"));
- if did.is_local() {
- try!(write!(f, "@{:?}", tcx.map.span(did.node)));
+ if let Some(node_id) = tcx.map.as_local_node_id(did) {
+ try!(write!(f, "@{:?}", tcx.map.span(node_id)));
let mut sep = " ";
- try!(tcx.with_freevars(did.node, |freevars| {
+ try!(tcx.with_freevars(node_id, |freevars| {
for (freevar, upvar_ty) in freevars.iter().zip(&substs.upvar_tys) {
- let node_id = freevar.def.local_node_id();
+ let node_id = freevar.def.var_id();
try!(write!(f,
"{}{}:{}",
sep,
f.write_str(match *self {
ty::StaticExplicitSelfCategory => "static",
ty::ByValueExplicitSelfCategory => "self",
- ty::ByReferenceExplicitSelfCategory(_, ast::MutMutable) => {
+ ty::ByReferenceExplicitSelfCategory(_, hir::MutMutable) => {
"&mut self"
}
- ty::ByReferenceExplicitSelfCategory(_, ast::MutImmutable) => "&self",
+ ty::ByReferenceExplicitSelfCategory(_, hir::MutImmutable) => "&self",
ty::ByBoxExplicitSelfCategory => "Box<self>",
})
}
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(box_syntax)]
-#![feature(fs_canonicalize)]
#![feature(libc)]
-#![feature(path_ext)]
#![feature(rand)]
#![feature(rustc_private)]
#![feature(slice_bytes)]
pub mod sha2;
pub mod svh;
pub mod target;
+pub mod slice;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem;
+
+pub fn ref_slice<T>(ptr: &T) -> &[T; 1] {
+ unsafe { mem::transmute(ptr) }
+}
+
+pub fn mut_ref_slice<T>(ptr: &mut T) -> &mut [T; 1] {
+ unsafe { mem::transmute(ptr) }
+}
pub use self::SawExprComponent::*;
pub use self::SawStmtComponent::*;
use self::SawAbiComponent::*;
- use syntax::ast::{self, NodeId, Ident};
+ use syntax::ast::{self, Name, NodeId};
use syntax::codemap::Span;
use syntax::parse::token;
use rustc_front::visit;
SawIdent(token::InternedString),
SawStructDef(token::InternedString),
- SawLifetimeRef(token::InternedString),
+ SawLifetime(token::InternedString),
SawLifetimeDef(token::InternedString),
SawMod,
SawVariant,
SawExplicitSelf,
SawPath,
- SawOptLifetimeRef,
SawBlock,
SawPat,
SawLocal,
SawExprTup,
SawExprBinary(hir::BinOp_),
SawExprUnary(hir::UnOp),
- SawExprLit(hir::Lit_),
+ SawExprLit(ast::Lit_),
SawExprCast,
SawExprIf,
SawExprWhile,
SawExprInlineAsm(&'a hir::InlineAsm),
SawExprStruct,
SawExprRepeat,
- SawExprParen,
}
fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
ExprBlock(..) => SawExprBlock,
ExprAssign(..) => SawExprAssign,
ExprAssignOp(op, _, _) => SawExprAssignOp(op.node),
- ExprField(_, id) => SawExprField(id.node.name.as_str()),
+ ExprField(_, name) => SawExprField(name.node.as_str()),
ExprTupField(_, id) => SawExprTupField(id.node),
ExprIndex(..) => SawExprIndex,
ExprRange(..) => SawExprRange,
ExprInlineAsm(ref asm) => SawExprInlineAsm(asm),
ExprStruct(..) => SawExprStruct,
ExprRepeat(..) => SawExprRepeat,
- ExprParen(..) => SawExprParen,
}
}
}
impl<'a, 'v> Visitor<'v> for StrictVersionHashVisitor<'a> {
- fn visit_struct_def(&mut self, s: &StructDef, ident: Ident,
- g: &Generics, _: NodeId) {
- SawStructDef(ident.name.as_str()).hash(self.st);
+ fn visit_variant_data(&mut self, s: &VariantData, name: Name,
+ g: &Generics, _: NodeId, _: Span) {
+ SawStructDef(name.as_str()).hash(self.st);
visit::walk_generics(self, g);
visit::walk_struct_def(self, s)
}
- fn visit_variant(&mut self, v: &Variant, g: &Generics) {
+ fn visit_variant(&mut self, v: &Variant, g: &Generics, item_id: NodeId) {
SawVariant.hash(self.st);
// walk_variant does not call walk_generics, so do it here.
visit::walk_generics(self, g);
- visit::walk_variant(self, v, g)
- }
-
- fn visit_opt_lifetime_ref(&mut self, _: Span, l: &Option<Lifetime>) {
- SawOptLifetimeRef.hash(self.st);
- // (This is a strange method in the visitor trait, in that
- // it does not expose a walk function to do the subroutine
- // calls.)
- match *l {
- Some(ref l) => self.visit_lifetime_ref(l),
- None => ()
- }
+ visit::walk_variant(self, v, g, item_id)
}
// All of the remaining methods just record (in the hash
// (If you edit a method such that it deviates from the
// pattern, please move that method up above this comment.)
- fn visit_ident(&mut self, _: Span, ident: Ident) {
- SawIdent(ident.name.as_str()).hash(self.st);
+ fn visit_name(&mut self, _: Span, name: Name) {
+ SawIdent(name.as_str()).hash(self.st);
}
- fn visit_lifetime_ref(&mut self, l: &Lifetime) {
- SawLifetimeRef(l.name.as_str()).hash(self.st);
+ fn visit_lifetime(&mut self, l: &Lifetime) {
+ SawLifetime(l.name.as_str()).hash(self.st);
}
fn visit_lifetime_def(&mut self, l: &LifetimeDef) {
SawPath.hash(self.st); visit::walk_path(self, path)
}
+ fn visit_path_list_item(&mut self, prefix: &Path, item: &'v PathListItem) {
+ SawPath.hash(self.st); visit::walk_path_list_item(self, prefix, item)
+ }
+
fn visit_block(&mut self, b: &Block) {
SawBlock.hash(self.st); visit::walk_block(self, b)
}
arch: "aarch64".to_string(),
target_os: "ios".to_string(),
target_env: "".to_string(),
+ target_vendor: "apple".to_string(),
options: TargetOptions {
features: "+neon,+fp-armv8,+cyclone".to_string(),
eliminate_frame_pointer: false,
arch: "aarch64".to_string(),
target_os: "android".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: super::android_base::opts(),
}
}
target_env: "gnu".to_string(),
arch: "aarch64".to_string(),
target_os: "linux".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
dll_suffix: ".dylib".to_string(),
archive_format: "bsd".to_string(),
pre_link_args: Vec::new(),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
}
arch: "arm".to_string(),
target_os: "android".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "arm".to_string(),
target_os: "linux".to_string(),
target_env: "gnueabi".to_string(),
+ target_vendor: "unknown".to_string(),
options: TargetOptions {
features: "+v6".to_string(),
arch: "arm".to_string(),
target_os: "linux".to_string(),
target_env: "gnueabihf".to_string(),
+ target_vendor: "unknown".to_string(),
options: TargetOptions {
features: "+v6,+vfp2".to_string(),
arch: "arm".to_string(),
target_os: "ios".to_string(),
target_env: "".to_string(),
+ target_vendor: "apple".to_string(),
options: TargetOptions {
features: "+v7,+vfp3,+neon".to_string(),
.. opts(Arch::Armv7)
arch: "arm".to_string(),
target_os: "ios".to_string(),
target_env: "".to_string(),
+ target_vendor: "apple".to_string(),
options: TargetOptions {
features: "+v7,+vfp4,+neon".to_string(),
.. opts(Arch::Armv7s)
has_rpath: true,
position_independent_executables: true,
archive_format: "gnu".to_string(),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: "alloc_system".to_string(),
.. Default::default()
}
),
position_independent_executables: true,
archive_format: "gnu".to_string(),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
}
executables: true,
has_rpath: true,
archive_format: "gnu".to_string(),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
arch: "x86".to_string(),
target_os: "ios".to_string(),
target_env: "".to_string(),
+ target_vendor: "apple".to_string(),
options: opts(Arch::I386)
}
}
arch: "x86".to_string(),
target_os: "macos".to_string(),
target_env: "".to_string(),
+ target_vendor: "apple".to_string(),
options: base,
}
}
arch: "x86".to_string(),
target_os: "android".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86".to_string(),
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "pc".to_string(),
options: options,
}
}
arch: "x86".to_string(),
target_os: "windows".to_string(),
target_env: "msvc".to_string(),
+ target_vendor: "pc".to_string(),
options: base,
}
}
arch: "x86".to_string(),
target_os: "dragonfly".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86".to_string(),
target_os: "freebsd".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::{Target, TargetOptions};
+
+pub fn target() -> Target {
+ let opts = TargetOptions {
+ linker: "pnacl-clang".to_string(),
+ ar: "pnacl-ar".to_string(),
+
+ pre_link_args: vec!("--pnacl-exceptions=sjlj".to_string(),
+ "--target=le32-unknown-nacl".to_string(),
+ "-Wl,--start-group".to_string()),
+ post_link_args: vec!("-Wl,--end-group".to_string()),
+ dynamic_linking: false,
+ executables: true,
+ exe_suffix: ".pexe".to_string(),
+ no_compiler_rt: false,
+ linker_is_gnu: true,
+ allow_asm: false,
+ archive_format: "gnu".to_string(),
+ .. Default::default()
+ };
+ Target {
+ llvm_target: "le32-unknown-nacl".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "32".to_string(),
+ target_os: "nacl".to_string(),
+ target_env: "newlib".to_string(),
+ target_vendor: "unknown".to_string(),
+ arch: "le32".to_string(),
+ options: opts,
+ }
+}
],
position_independent_executables: true,
archive_format: "gnu".to_string(),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
}
arch: "mips".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
options: super::linux_base::opts()
}
}
arch: "mips".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
options: super::linux_base::opts()
}
pub target_os: String,
/// Environment name to use for conditional compilation.
pub target_env: String,
+ /// Vendor name to use for conditional compilation.
+ pub target_vendor: String,
/// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm",
/// "aarch64", "mips", and "powerpc". "mips" includes "mipsel".
pub arch: String,
/// Whether to disable linking to compiler-rt. Defaults to false, as LLVM
/// will emit references to the functions that compiler-rt provides.
pub no_compiler_rt: bool,
+ /// Whether to disable linking to the default libraries, typically corresponds
+ /// to `-nodefaultlibs`. Defaults to true.
+ pub no_default_libraries: bool,
/// Dynamically linked executables can be compiled as position independent
/// if the default relocation model of position independent code is not
/// changed. This is a requirement to take advantage of ASLR, as otherwise
linker_is_gnu: false,
has_rpath: false,
no_compiler_rt: false,
+ no_default_libraries: true,
position_independent_executables: false,
pre_link_objects: Vec::new(),
post_link_objects: Vec::new(),
}
};
+ let get_opt_field = |name: &str, default: &str| {
+ obj.find(name).and_then(|s| s.as_string())
+ .map(|s| s.to_string())
+ .unwrap_or(default.to_string())
+ };
+
let mut base = Target {
llvm_target: get_req_field("llvm-target"),
target_endian: get_req_field("target-endian"),
target_pointer_width: get_req_field("target-pointer-width"),
arch: get_req_field("arch"),
target_os: get_req_field("os"),
- target_env: obj.find("env").and_then(|s| s.as_string())
- .map(|s| s.to_string()).unwrap_or(String::new()),
+ target_env: get_opt_field("env", ""),
+ target_vendor: get_opt_field("vendor", "unknown"),
options: Default::default(),
};
key!(linker_is_gnu, bool);
key!(has_rpath, bool);
key!(no_compiler_rt, bool);
+ key!(no_default_libraries, bool);
key!(pre_link_args, list);
key!(post_link_args, list);
key!(allow_asm, bool);
x86_64_unknown_bitrig,
x86_64_unknown_openbsd,
x86_64_unknown_netbsd,
+ x86_64_rumprun_netbsd,
x86_64_apple_darwin,
i686_apple_darwin,
i686_pc_windows_gnu,
x86_64_pc_windows_msvc,
- i686_pc_windows_msvc
+ i686_pc_windows_msvc,
+
+ le32_unknown_nacl
);
}
}
-fn best_allocator() -> String {
+fn maybe_jemalloc() -> String {
if cfg!(disable_jemalloc) {
"alloc_system".to_string()
} else {
),
position_independent_executables: true,
archive_format: "gnu".to_string(),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: "alloc_system".to_string(),
.. Default::default()
}
}
arch: "powerpc".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
exe_suffix: ".exe".to_string(),
staticlib_prefix: "".to_string(),
staticlib_suffix: ".lib".to_string(),
+ // Unfortunately right now passing -nodefaultlibs to gcc on windows
+ // doesn't work so hot (in terms of native dependencies). This flag
+ // should hopefully be removed one day though!
+ no_default_libraries: false,
is_like_windows: true,
archive_format: "gnu".to_string(),
pre_link_args: vec!(
// Always enable DEP (NX bit) when it is available
"-Wl,--nxcompat".to_string(),
),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: super::maybe_jemalloc(),
.. Default::default()
}
"/NXCOMPAT".to_string(),
],
archive_format: "gnu".to_string(),
- exe_allocation_crate: super::best_allocator(),
+ exe_allocation_crate: "alloc_system".to_string(),
.. Default::default()
}
arch: "x86_64".to_string(),
target_os: "macos".to_string(),
target_env: "".to_string(),
+ target_vendor: "apple".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "ios".to_string(),
target_env: "".to_string(),
+ target_vendor: "apple".to_string(),
options: opts(Arch::X86_64)
}
}
arch: "x86_64".to_string(),
target_os: "windows".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "pc".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "windows".to_string(),
target_env: "msvc".to_string(),
+ target_vendor: "pc".to_string(),
options: base,
}
}
--- /dev/null
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use target::Target;
+
+pub fn target() -> Target {
+ let mut base = super::netbsd_base::opts();
+ base.pre_link_args.push("-m64".to_string());
+ base.linker = "x86_64-rumprun-netbsd-gcc".to_string();
+ base.ar = "x86_64-rumprun-netbsd-ar".to_string();
+
+ base.dynamic_linking = false;
+ base.has_rpath = false;
+ base.position_independent_executables = false;
+ base.disable_redzone = true;
+ base.no_default_libraries = false;
+
+ Target {
+ llvm_target: "x86_64-rumprun-netbsd".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ arch: "x86_64".to_string(),
+ target_os: "netbsd".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "rumprun".to_string(),
+ options: base,
+ }
+}
arch: "x86_64".to_string(),
target_os: "bitrig".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "dragonfly".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "freebsd".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "linux".to_string(),
target_env: "gnu".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "linux".to_string(),
target_env: "musl".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "netbsd".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
arch: "x86_64".to_string(),
target_os: "openbsd".to_string(),
target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
options: base,
}
}
//! A typesafe bitmask flag generator.
-#[cfg(test)] #[macro_use] extern crate std;
+#[cfg(test)]
+#[macro_use]
+extern crate std;
/// The `bitflags!` macro generates a `struct` that holds a set of C-style
/// bitmask flags. It is useful for creating typesafe wrappers for C APIs.
}
#[test]
- fn test_bits(){
+ fn test_bits() {
assert_eq!(Flags::empty().bits(), 0b00000000);
assert_eq!(Flags::FlagA.bits(), 0b00000001);
assert_eq!(Flags::FlagABC.bits(), 0b00000111);
}
#[test]
- fn test_is_empty(){
+ fn test_is_empty() {
assert!(Flags::empty().is_empty());
assert!(!Flags::FlagA.is_empty());
assert!(!Flags::FlagABC.is_empty());
}
#[test]
- fn test_insert(){
+ fn test_insert() {
let mut e1 = Flags::FlagA;
let e2 = Flags::FlagA | Flags::FlagB;
e1.insert(e2);
}
#[test]
- fn test_remove(){
+ fn test_remove() {
let mut e1 = Flags::FlagA | Flags::FlagB;
let e2 = Flags::FlagA | Flags::FlagC;
e1.remove(e2);
#[test]
fn test_hash() {
- let mut x = Flags::empty();
- let mut y = Flags::empty();
- assert!(hash(&x) == hash(&y));
- x = Flags::all();
- y = Flags::FlagABC;
- assert!(hash(&x) == hash(&y));
+ let mut x = Flags::empty();
+ let mut y = Flags::empty();
+ assert!(hash(&x) == hash(&y));
+ x = Flags::all();
+ y = Flags::FlagABC;
+ assert!(hash(&x) == hash(&y));
}
fn hash<T: Hash>(t: &T) -> u64 {
let new_loan_indices = self.loans_generated_by(node);
debug!("new_loan_indices = {:?}", new_loan_indices);
- self.each_issued_loan(node, |issued_loan| {
- for &new_loan_index in &new_loan_indices {
+ for &new_loan_index in &new_loan_indices {
+ self.each_issued_loan(node, |issued_loan| {
let new_loan = &self.all_loans[new_loan_index];
- self.report_error_if_loans_conflict(issued_loan, new_loan);
- }
- true
- });
+ // Only report an error for the first issued loan that conflicts
+ // to avoid O(n^2) errors.
+ self.report_error_if_loans_conflict(issued_loan, new_loan)
+ });
+ }
for (i, &x) in new_loan_indices.iter().enumerate() {
let old_loan = &self.all_loans[x];
pub fn report_error_if_loans_conflict(&self,
old_loan: &Loan<'tcx>,
- new_loan: &Loan<'tcx>) {
+ new_loan: &Loan<'tcx>)
+ -> bool {
//! Checks whether `old_loan` and `new_loan` can safely be issued
//! simultaneously.
self.report_error_if_loan_conflicts_with_restriction(
old_loan, new_loan, old_loan, new_loan) &&
self.report_error_if_loan_conflicts_with_restriction(
- new_loan, old_loan, old_loan, new_loan);
+ new_loan, old_loan, old_loan, new_loan)
}
pub fn report_error_if_loan_conflicts_with_restriction(&self,
match (new_loan.kind, old_loan.kind) {
(ty::MutBorrow, ty::MutBorrow) => {
- self.bccx.span_err(
- new_loan.span,
- &format!("cannot borrow `{}`{} as mutable \
- more than once at a time",
- nl, new_loan_msg))
+ span_err!(self.bccx, new_loan.span, E0499,
+ "cannot borrow `{}`{} as mutable \
+ more than once at a time",
+ nl, new_loan_msg);
}
(ty::UniqueImmBorrow, _) => {
- self.bccx.span_err(
- new_loan.span,
- &format!("closure requires unique access to `{}` \
- but {} is already borrowed{}",
- nl, ol_pronoun, old_loan_msg));
+ span_err!(self.bccx, new_loan.span, E0500,
+ "closure requires unique access to `{}` \
+ but {} is already borrowed{}",
+ nl, ol_pronoun, old_loan_msg);
}
(_, ty::UniqueImmBorrow) => {
- self.bccx.span_err(
- new_loan.span,
- &format!("cannot borrow `{}`{} as {} because \
- previous closure requires unique access",
- nl, new_loan_msg, new_loan.kind.to_user_str()));
+ span_err!(self.bccx, new_loan.span, E0501,
+ "cannot borrow `{}`{} as {} because \
+ previous closure requires unique access",
+ nl, new_loan_msg, new_loan.kind.to_user_str());
}
(_, _) => {
- self.bccx.span_err(
- new_loan.span,
- &format!("cannot borrow `{}`{} as {} because \
- {} is also borrowed as {}{}",
- nl,
- new_loan_msg,
- new_loan.kind.to_user_str(),
- ol_pronoun,
- old_loan.kind.to_user_str(),
- old_loan_msg));
+ span_err!(self.bccx, new_loan.span, E0502,
+ "cannot borrow `{}`{} as {} because \
+ {} is also borrowed as {}{}",
+ nl,
+ new_loan_msg,
+ new_loan.kind.to_user_str(),
+ ol_pronoun,
+ old_loan.kind.to_user_str(),
+ old_loan_msg);
}
}
match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
UseOk => { }
UseWhileBorrowed(loan_path, loan_span) => {
- self.bccx.span_err(
- span,
- &format!("cannot use `{}` because it was mutably borrowed",
- &self.bccx.loan_path_to_string(copy_path))
- );
+ span_err!(self.bccx, span, E0503,
+ "cannot use `{}` because it was mutably borrowed",
+ &self.bccx.loan_path_to_string(copy_path));
self.bccx.span_note(
loan_span,
&format!("borrow of `{}` occurs here",
match self.analyze_restrictions_on_use(id, move_path, ty::MutBorrow) {
UseOk => { }
UseWhileBorrowed(loan_path, loan_span) => {
- let err_message = match move_kind {
+ match move_kind {
move_data::Captured =>
- format!("cannot move `{}` into closure because it is borrowed",
- &self.bccx.loan_path_to_string(move_path)),
+ span_err!(self.bccx, span, E0504,
+ "cannot move `{}` into closure because it is borrowed",
+ &self.bccx.loan_path_to_string(move_path)),
move_data::Declared |
move_data::MoveExpr |
move_data::MovePat =>
- format!("cannot move out of `{}` because it is borrowed",
- &self.bccx.loan_path_to_string(move_path))
+ span_err!(self.bccx, span, E0505,
+ "cannot move out of `{}` because it is borrowed",
+ &self.bccx.loan_path_to_string(move_path))
};
- self.bccx.span_err(span, &err_message[..]);
self.bccx.span_note(
loan_span,
&format!("borrow of `{}` occurs here",
span: Span,
loan_path: &LoanPath<'tcx>,
loan: &Loan) {
- self.bccx.span_err(
- span,
- &format!("cannot assign to `{}` because it is borrowed",
- self.bccx.loan_path_to_string(loan_path)));
+ span_err!(self.bccx, span, E0506,
+ "cannot assign to `{}` because it is borrowed",
+ self.bccx.loan_path_to_string(loan_path));
self.bccx.span_note(
loan.span,
&format!("borrow of `{}` occurs here",
use borrowck::LoanPathElem::{LpDeref, LpInterior};
use borrowck::move_data::InvalidMovePathIndex;
use borrowck::move_data::{MoveData, MovePathIndex};
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
+use rustc::middle::def_id::{DefId};
use rustc::middle::ty;
use rustc::middle::mem_categorization as mc;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::Span;
-use rustc_front::attr::AttrMetaMethods;
+use syntax::attr::AttrMetaMethods;
#[derive(PartialEq, Eq, PartialOrd, Ord)]
enum Fragment {
}
let mut fraginfo_map = this.tcx.fragment_infos.borrow_mut();
- let fn_did = DefId { krate: LOCAL_CRATE, node: id };
+ let fn_did = this.tcx.map.local_def_id(id);
let prev = fraginfo_map.insert(fn_did, fragment_infos);
assert!(prev.is_none());
}
/// FIXME(pnkfelix) probably do not want/need
/// `parents_of_fragments` at all, if we can avoid it.
///
- /// Update: I do not see a way to to avoid it. Maybe just remove
+ /// Update: I do not see a way to avoid it. Maybe just remove
/// above fixme, or at least document why doing this may be hard.
parents_of_fragments: Vec<MovePathIndex>,
let pat_span_path_opt = match move_pat.node {
hir::PatIdent(_, ref path1, _) => {
Some(MoveSpanAndPath{span: move_pat.span,
- ident: path1.node})
+ name: path1.node.name})
},
_ => None,
};
use std::cell::RefCell;
use syntax::ast;
use syntax::codemap;
-use rustc_front::print::pprust;
use rustc_front::hir;
pub struct MoveErrorCollector<'tcx> {
#[derive(Clone)]
pub struct MoveSpanAndPath {
pub span: codemap::Span,
- pub ident: ast::Ident
+ pub name: ast::Name,
}
pub struct GroupedMoveErrors<'tcx> {
let mut is_first_note = true;
for move_to in &error.move_to_places {
note_move_destination(bccx, move_to.span,
- &move_to.ident, is_first_note);
+ move_to.name, is_first_note);
is_first_note = false;
}
}
mc::cat_deref(_, _, mc::Implicit(..)) |
mc::cat_deref(_, _, mc::UnsafePtr(..)) |
mc::cat_static_item => {
- bccx.span_err(move_from.span,
- &format!("cannot move out of {}",
- move_from.descriptive_string(bccx.tcx)));
+ span_err!(bccx, move_from.span, E0507,
+ "cannot move out of {}",
+ move_from.descriptive_string(bccx.tcx));
}
mc::cat_interior(ref b, mc::InteriorElement(Kind::Index, _)) => {
let expr = bccx.tcx.map.expect_expr(move_from.id);
if let hir::ExprIndex(..) = expr.node {
- bccx.span_err(move_from.span,
- &format!("cannot move out of type `{}`, \
- a non-copy fixed-size array",
- b.ty));
+ span_err!(bccx, move_from.span, E0508,
+ "cannot move out of type `{}`, \
+ a non-copy fixed-size array",
+ b.ty);
}
}
match b.ty.sty {
ty::TyStruct(def, _) |
ty::TyEnum(def, _) if def.has_dtor() => {
- bccx.span_err(
- move_from.span,
- &format!("cannot move out of type `{}`, \
- which defines the `Drop` trait",
- b.ty));
+ span_err!(bccx, move_from.span, E0509,
+ "cannot move out of type `{}`, \
+ which defines the `Drop` trait",
+ b.ty);
},
_ => {
bccx.span_bug(move_from.span, "this path should not cause illegal move")
fn note_move_destination(bccx: &BorrowckCtxt,
move_to_span: codemap::Span,
- pat_ident: &ast::Ident,
+ pat_name: ast::Name,
is_first_note: bool) {
- let pat_name = pprust::ident_to_string(pat_ident);
if is_first_note {
bccx.span_note(
move_to_span,
// A local, "cleaned" version of `mc::InteriorKind` that drops
// information that is not relevant to loan-path analysis. (In
-// particular, the distinction between how precisely a array-element
+// particular, the distinction between how precisely an array-element
// is tracked is irrelevant here.)
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum InteriorKind {
self.tcx.sess.span_err(s, m);
}
+ pub fn span_err_with_code(&self, s: Span, msg: &str, code: &str) {
+ self.tcx.sess.span_err_with_code(s, msg, code);
+ }
+
pub fn span_bug(&self, s: Span, m: &str) {
self.tcx.sess.span_bug(s, m);
}
You can read more about cell types in the API documentation:
https://doc.rust-lang.org/std/cell/
-"##
+"##,
+
+E0499: r##"
+A variable was borrowed as mutable more than once. Erroneous code example:
+
+```
+let mut i = 0;
+let mut x = &mut i;
+let mut a = &mut i;
+// error: cannot borrow `i` as mutable more than once at a time
+```
+
+Please note that in rust, you can either have many immutable references, or one
+mutable reference. Take a look at
+https://doc.rust-lang.org/stable/book/references-and-borrowing.html for more
+information. Example:
+
+
+```
+let mut i = 0;
+let mut x = &mut i; // ok!
+
+// or:
+let mut i = 0;
+let a = &i; // ok!
+let b = &i; // still ok!
+let c = &i; // still ok!
+```
+"##,
}
register_diagnostics! {
E0385, // {} in an aliasable location
E0388, // {} in a static location
- E0389 // {} in a `&` reference
+ E0389, // {} in a `&` reference
+ E0500, // closure requires unique access to `..` but .. is already borrowed
+ E0501, // cannot borrow `..`.. as .. because previous closure requires unique access
+ E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
+ E0503, // cannot use `..` because it was mutably borrowed
+ E0504, // cannot move `..` into closure because it is borrowed
+ E0505, // cannot move out of `..` because it is borrowed
+ E0506, // cannot assign to `..` because it is borrowed
+ E0507, // cannot move out of ..
+ E0508, // cannot move out of type `..`, a non-copy fixed-size array
+ E0509, // cannot move out of type `..`, which defines the `Drop` trait
}
use rustc::front::map as hir_map;
use rustc_mir as mir;
use rustc::session::Session;
-use rustc::session::config::{self, Input, OutputFilenames};
+use rustc::session::config::{self, Input, OutputFilenames, OutputType};
use rustc::session::search_paths::PathKind;
use rustc::lint;
use rustc::metadata;
use rustc_typeck as typeck;
use rustc_privacy;
use rustc_front::hir;
-use rustc_front::lowering::lower_crate;
+use rustc_front::lowering::{lower_crate, LoweringContext};
use super::Compilation;
use serialize::json;
+use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs;
use std::io::{self, Write};
use std::path::{Path, PathBuf};
-use syntax::ast;
+use syntax::ast::{self, NodeIdAssigner};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::diagnostics;
+use syntax::feature_gate::UnstableFeatures;
use syntax::fold::Folder;
use syntax::parse;
use syntax::parse::token;
// We need nested scopes here, because the intermediate results can keep
// large chunks of memory alive and we want to free them as soon as
// possible to keep the peak memory usage low
- let (sess, result) = {
+ let result = {
let (outputs, expanded_crate, id) = {
let krate = phase_1_parse_input(&sess, cfg, input);
let expanded_crate = assign_node_ids(&sess, expanded_crate);
// Lower ast -> hir.
+ let lcx = LoweringContext::new(&sess, Some(&expanded_crate));
let mut hir_forest = time(sess.time_passes(),
"lowering ast -> hir",
- || hir_map::Forest::new(lower_crate(&expanded_crate)));
+ || hir_map::Forest::new(lower_crate(&lcx, &expanded_crate)));
let arenas = ty::CtxtArenas::new();
let ast_map = make_map(&sess, &mut hir_forest);
- write_out_deps(&sess, input, &outputs, &id[..]);
+ write_out_deps(&sess, &outputs, &id);
controller_entry_point!(after_write_deps,
sess,
&ast_map,
&expanded_crate,
&ast_map.krate(),
- &id[..]));
+ &id[..],
+ &lcx));
+ time(sess.time_passes(), "attribute checking", || {
+ front::check_attr::check_crate(&sess, &expanded_crate);
+ });
+
+ time(sess.time_passes(), "early lint checks", || {
+ lint::check_ast_crate(&sess, &expanded_crate)
+ });
- phase_3_run_analysis_passes(sess,
+ phase_3_run_analysis_passes(&sess,
ast_map,
- &expanded_crate,
&arenas,
- id,
+ &id,
control.make_glob_map,
|tcx, analysis| {
&expanded_crate,
tcx.map.krate(),
&analysis,
- tcx);
+ tcx,
+ &lcx,
+ &id);
(control.after_analysis.callback)(state);
tcx.sess.abort_if_errors();
pub expanded_crate: Option<&'a ast::Crate>,
pub hir_crate: Option<&'a hir::Crate>,
pub ast_map: Option<&'a hir_map::Map<'ast>>,
- pub analysis: Option<&'a ty::CrateAnalysis>,
+ pub analysis: Option<&'a ty::CrateAnalysis<'a>>,
pub tcx: Option<&'a ty::ctxt<'tcx>>,
+ pub lcx: Option<&'a LoweringContext<'a>>,
pub trans: Option<&'a trans::CrateTranslation>,
}
ast_map: None,
analysis: None,
tcx: None,
+ lcx: None,
trans: None,
}
}
ast_map: &'a hir_map::Map<'ast>,
krate: &'a ast::Crate,
hir_crate: &'a hir::Crate,
- crate_name: &'a str)
+ crate_name: &'a str,
+ lcx: &'a LoweringContext<'a>)
-> CompileState<'a, 'ast, 'tcx> {
CompileState {
crate_name: Some(crate_name),
ast_map: Some(ast_map),
krate: Some(krate),
hir_crate: Some(hir_crate),
+ lcx: Some(lcx),
.. CompileState::empty(input, session, out_dir)
}
}
krate: &'a ast::Crate,
hir_crate: &'a hir::Crate,
analysis: &'a ty::CrateAnalysis,
- tcx: &'a ty::ctxt<'tcx>)
+ tcx: &'a ty::ctxt<'tcx>,
+ lcx: &'a LoweringContext<'a>,
+ crate_name: &'a str)
-> CompileState<'a, 'ast, 'tcx> {
CompileState {
analysis: Some(analysis),
tcx: Some(tcx),
krate: Some(krate),
hir_crate: Some(hir_crate),
+ lcx: Some(lcx),
+ crate_name: Some(crate_name),
.. CompileState::empty(input, session, out_dir)
}
}
}
});
- let Registry { syntax_exts, lint_passes, lint_groups,
+ let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
llvm_passes, attributes, .. } = registry;
{
let mut ls = sess.lint_store.borrow_mut();
- for pass in lint_passes {
- ls.register_pass(Some(sess), true, pass);
+ for pass in early_lint_passes {
+ ls.register_early_pass(Some(sess), true, pass);
+ }
+ for pass in late_lint_passes {
+ ls.register_late_pass(Some(sess), true, pass);
}
for (name, to) in lint_groups {
/// Run the resolution, typechecking, region checking and other
/// miscellaneous analysis passes on the crate. Return various
/// structures carrying the results of the analysis.
-pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
+pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
ast_map: front::map::Map<'tcx>,
- ast_crate: &ast::Crate,
arenas: &'tcx ty::CtxtArenas<'tcx>,
- name: String,
+ name: &str,
make_glob_map: resolve::MakeGlobMap,
f: F)
- -> (Session, R)
+ -> R
where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>,
ty::CrateAnalysis) -> R
{
let krate = ast_map.krate();
time(time_passes, "external crate/lib resolution", ||
- LocalCrateReader::new(&sess, &ast_map).read_crates(krate));
+ LocalCrateReader::new(sess, &ast_map).read_crates(krate));
let lang_items = time(time_passes, "language item collection", ||
- middle::lang_items::collect_language_items(krate, &sess));
+ middle::lang_items::collect_language_items(&sess, &ast_map));
let resolve::CrateMap {
def_map,
glob_map,
} =
time(time_passes, "resolution",
- || resolve::resolve_crate(&sess, &ast_map, make_glob_map));
+ || resolve::resolve_crate(sess, &ast_map, make_glob_map));
// Discard MTWT tables that aren't required past resolution.
- syntax::ext::mtwt::clear_tables();
+ // FIXME: get rid of uses of MTWT tables in typeck, mir and trans and clear them
+ if !sess.opts.debugging_opts.keep_mtwt_tables {
+ // syntax::ext::mtwt::clear_tables();
+ }
let named_region_map = time(time_passes, "lifetime resolution",
- || middle::resolve_lifetime::krate(&sess, krate, &def_map));
+ || middle::resolve_lifetime::krate(sess, krate, &def_map));
time(time_passes, "looking for entry point",
- || middle::entry::find_entry_point(&sess, &ast_map));
+ || middle::entry::find_entry_point(sess, &ast_map));
sess.plugin_registrar_fn.set(
time(time_passes, "looking for plugin registrar", ||
sess.diagnostic(), krate)));
let region_map = time(time_passes, "region resolution", ||
- middle::region::resolve_crate(&sess, krate));
+ middle::region::resolve_crate(sess, krate));
time(time_passes, "loop checking", ||
- middle::check_loop::check_crate(&sess, krate));
+ middle::check_loop::check_crate(sess, krate));
time(time_passes, "static item recursion checking", ||
- middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
+ middle::check_static_recursion::check_crate(sess, krate, &def_map, &ast_map));
ty::ctxt::create_and_enter(sess,
arenas,
// passes are timed inside typeck
typeck::check_crate(tcx, trait_map);
- time(time_passes, "MIR dump", ||
- mir::dump::dump_crate(tcx));
-
time(time_passes, "const checking", ||
middle::check_const::check_crate(tcx));
time(time_passes, "match checking", ||
middle::check_match::check_crate(tcx));
+ match tcx.sess.opts.unstable_features {
+ UnstableFeatures::Disallow => {
+ // use this as a shorthand for beta/stable, and skip
+ // MIR construction there until known regressions are
+ // addressed
+ }
+ UnstableFeatures::Allow | UnstableFeatures::Cheat => {
+ let _mir_map =
+ time(time_passes, "MIR dump", ||
+ mir::mir_map::build_mir_for_crate(tcx));
+ }
+ }
+
time(time_passes, "liveness checking", ||
middle::liveness::check_crate(tcx));
&tcx.sess, lib_features_used));
time(time_passes, "lint checking", ||
- lint::check_crate(tcx, &lower_crate(ast_crate), &exported_items));
+ lint::check_crate(tcx, krate, &exported_items));
// The above three passes generate errors w/o aborting
tcx.sess.abort_if_errors();
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) {
if sess.opts.cg.no_integrated_as {
- let output_type = config::OutputTypeAssembly;
-
+ let mut map = HashMap::new();
+ map.insert(OutputType::Assembly, None);
time(sess.time_passes(), "LLVM passes", ||
- write::run_passes(sess, trans, &[output_type], outputs));
+ write::run_passes(sess, trans, &map, outputs));
write::run_assembler(sess, outputs);
// Remove assembly source, unless --save-temps was specified
if !sess.opts.cg.save_temps {
- fs::remove_file(&outputs.temp_path(config::OutputTypeAssembly)).unwrap();
+ fs::remove_file(&outputs.temp_path(OutputType::Assembly)).unwrap();
}
} else {
time(sess.time_passes(), "LLVM passes", ||
filename.replace(" ", "\\ ")
}
-fn write_out_deps(sess: &Session,
- input: &Input,
- outputs: &OutputFilenames,
- id: &str) {
-
+fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) {
let mut out_filenames = Vec::new();
- for output_type in &sess.opts.output_types {
+ for output_type in sess.opts.output_types.keys() {
let file = outputs.path(*output_type);
match *output_type {
- config::OutputTypeExe => {
+ OutputType::Exe => {
for output in sess.crate_types.borrow().iter() {
let p = link::filename_for_input(sess, *output, id,
outputs);
}
}
- // Write out dependency rules to the dep-info file if requested with
- // --dep-info
- let deps_filename = match sess.opts.write_dependency_info {
- // Use filename from --dep-file argument if given
- (true, Some(ref filename)) => filename.clone(),
- // Use default filename: crate source filename with extension replaced
- // by ".d"
- (true, None) => match *input {
- Input::File(..) => outputs.with_extension("d"),
- Input::Str(..) => {
- sess.warn("can not write --dep-info without a filename \
- when compiling stdin.");
- return
- },
- },
- _ => return,
- };
+ // Write out dependency rules to the dep-info file if requested
+ if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
+ return
+ }
+ let deps_filename = outputs.path(OutputType::DepInfo);
let result = (|| -> io::Result<()> {
// Build a list of files used to compile the output and
.collect();
let mut file = try!(fs::File::create(&deps_filename));
for path in &out_filenames {
- try!(write!(&mut file,
+ try!(write!(file,
"{}: {}\n\n", path.display(), files.join(" ")));
}
+
+ // Emit a fake target for each input file to the compilation. This
+ // prevents `make` from spitting out an error if a file is later
+ // deleted. For more info see #28735
+ for path in files {
+ try!(writeln!(file, "{}:", path));
+ }
Ok(())
})();
out_filestem: stem,
single_output_file: None,
extra: sess.opts.cg.extra_filename.clone(),
+ outputs: sess.opts.output_types.clone(),
}
}
Some(ref out_file) => {
- let ofile = if sess.opts.output_types.len() > 1 {
+ let unnamed_output_types = sess.opts.output_types.values()
+ .filter(|a| a.is_none())
+ .count();
+ let ofile = if unnamed_output_types > 1 {
sess.warn("ignoring specified output filename because multiple \
outputs were requested");
None
.to_str().unwrap().to_string(),
single_output_file: ofile,
extra: sess.opts.cg.extra_filename.clone(),
+ outputs: sess.opts.output_types.clone(),
}
}
}
use rustc_trans::back::link;
use rustc_trans::save;
use rustc::session::{config, Session, build_session};
-use rustc::session::config::{Input, PrintRequest};
+use rustc::session::config::{Input, PrintRequest, OutputType};
use rustc::lint::Lint;
use rustc::lint;
use rustc::metadata;
-> Compilation {
match matches.opt_str("explain") {
Some(ref code) => {
- match descriptions.find_description(&code[..]) {
+ let normalised = if !code.starts_with("E") {
+ format!("E{0:0>4}", code)
+ } else {
+ code.to_string()
+ };
+ match descriptions.find_description(&normalised) {
Some(ref description) => {
// Slice off the leading newline and print.
print!("{}", &description[1..]);
control.after_analysis.stop = Compilation::Stop;
}
- if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) {
+ if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) {
control.after_llvm.stop = Compilation::Stop;
}
time(state.session.time_passes(),
"save analysis",
|| save::process_crate(state.tcx.unwrap(),
+ state.lcx.unwrap(),
state.krate.unwrap(),
state.analysis.unwrap(),
+ state.crate_name.unwrap(),
state.out_dir));
};
control.make_glob_map = resolve::MakeGlobMap::Yes;
use syntax::codemap;
use syntax::fold::{self, Folder};
use syntax::print::{pp, pprust};
+use syntax::print::pprust::PrintState;
use syntax::ptr::P;
use syntax::util::small_vector::SmallVector;
use rustc::front::map as hir_map;
use rustc::front::map::{blocks, NodePrinter};
use rustc_front::hir;
-use rustc_front::lowering::lower_crate;
+use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_front::print::pprust as pprust_hir;
#[derive(Copy, Clone, PartialEq, Debug)]
impl PpSourceMode {
/// Constructs a `PrinterSupport` object and passes it to `f`.
fn call_with_pp_support<'tcx, A, B, F>(&self,
- sess: Session,
+ sess: &'tcx Session,
ast_map: Option<hir_map::Map<'tcx>>,
payload: B,
f: F) -> A where
}
}
fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
- sess: Session,
+ sess: &'tcx Session,
ast_map: &hir_map::Map<'tcx>,
- ast_crate: &ast::Crate,
arenas: &'tcx ty::CtxtArenas<'tcx>,
- id: String,
+ id: &str,
payload: B,
f: F) -> A where
F: FnOnce(&HirPrinterSupport, B, &hir::Crate) -> A,
PpmTyped => {
driver::phase_3_run_analysis_passes(sess,
ast_map.clone(),
- ast_crate,
arenas,
id,
resolve::MakeGlobMap::No,
|tcx, _| {
let annotation = TypedAnnotation { tcx: tcx };
f(&annotation, payload, &ast_map.forest.krate)
- }).1
+ })
}
_ => panic!("Should use call_with_pp_support"),
}
}
struct NoAnn<'ast> {
- sess: Session,
+ sess: &'ast Session,
ast_map: Option<hir_map::Map<'ast>>
}
impl<'ast> PrinterSupport<'ast> for NoAnn<'ast> {
- fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+ fn sess<'a>(&'a self) -> &'a Session { self.sess }
fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
self.ast_map.as_ref()
}
impl<'ast> HirPrinterSupport<'ast> for NoAnn<'ast> {
- fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+ fn sess<'a>(&'a self) -> &'a Session { self.sess }
fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
self.ast_map.as_ref()
impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
struct IdentifiedAnnotation<'ast> {
- sess: Session,
+ sess: &'ast Session,
ast_map: Option<hir_map::Map<'ast>>,
}
impl<'ast> PrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
- fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+ fn sess<'a>(&'a self) -> &'a Session { self.sess }
fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
self.ast_map.as_ref()
}
impl<'ast> HirPrinterSupport<'ast> for IdentifiedAnnotation<'ast> {
- fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+ fn sess<'a>(&'a self) -> &'a Session { self.sess }
fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
self.ast_map.as_ref()
s: &mut pprust_hir::State,
node: pprust_hir::AnnNode) -> io::Result<()> {
match node {
- pprust_hir::NodeIdent(_) | pprust_hir::NodeName(_) => Ok(()),
-
+ pprust_hir::NodeName(_) => Ok(()),
pprust_hir::NodeItem(item) => {
try!(pp::space(&mut s.s));
s.synth_comment(item.id.to_string())
}
struct HygieneAnnotation<'ast> {
- sess: Session,
+ sess: &'ast Session,
ast_map: Option<hir_map::Map<'ast>>,
}
impl<'ast> PrinterSupport<'ast> for HygieneAnnotation<'ast> {
- fn sess<'a>(&'a self) -> &'a Session { &self.sess }
+ fn sess<'a>(&'a self) -> &'a Session { self.sess }
fn ast_map<'a>(&'a self) -> Option<&'a hir_map::Map<'ast>> {
self.ast_map.as_ref()
try!(pp::space(&mut s.s));
// FIXME #16420: this doesn't display the connections
// between syntax contexts
- s.synth_comment(format!("{}#{}", nm, ctxt))
+ s.synth_comment(format!("{}#{}", nm, ctxt.0))
}
pprust::NodeName(&ast::Name(nm)) => {
try!(pp::space(&mut s.s));
// There is some twisted, god-forsaken tangle of lifetimes here which makes
// the ordering of stuff super-finicky.
let mut hir_forest;
+ let lcx = LoweringContext::new(&sess, Some(&krate));
let arenas = ty::CtxtArenas::new();
let ast_map = if compute_ast_map {
- hir_forest = hir_map::Forest::new(lower_crate(&krate));
+ hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate));
let map = driver::make_map(&sess, &mut hir_forest);
Some(map)
} else {
// Silently ignores an identified node.
let out: &mut Write = &mut out;
s.call_with_pp_support(
- sess, ast_map, box out, |annotation, out| {
+ &sess, ast_map, box out, |annotation, out| {
debug!("pretty printing source code {:?}", s);
let sess = annotation.sess();
pprust::print_crate(sess.codemap(),
(PpmHir(s), None) => {
let out: &mut Write = &mut out;
s.call_with_pp_support_hir(
- sess, &ast_map.unwrap(), &krate, &arenas, id, box out, |annotation, out, krate| {
+ &sess, &ast_map.unwrap(), &arenas, &id, box out, |annotation, out, krate| {
debug!("pretty printing source code {:?}", s);
let sess = annotation.sess();
pprust_hir::print_crate(sess.codemap(),
(PpmHir(s), Some(uii)) => {
let out: &mut Write = &mut out;
- s.call_with_pp_support_hir(sess,
+ s.call_with_pp_support_hir(&sess,
&ast_map.unwrap(),
- &krate,
&arenas,
- id,
+ &id,
(out,uii),
|annotation, (out,uii), _| {
debug!("pretty printing source code {:?}", s);
match code {
Some(code) => {
let variants = gather_flowgraph_variants(&sess);
- driver::phase_3_run_analysis_passes(sess,
+ driver::phase_3_run_analysis_passes(&sess,
ast_map,
- &krate,
&arenas,
- id,
+ &id,
resolve::MakeGlobMap::No,
|tcx, _| {
print_flowgraph(variants, tcx, code, mode, out)
- }).1
+ })
}
None => {
let message = format!("--pretty=flowgraph needs \
use syntax::parse::token;
use syntax::feature_gate::UnstableFeatures;
-use rustc_front::lowering::lower_crate;
+use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_front::hir;
struct Env<'a, 'tcx: 'a> {
.expect("phase 2 aborted");
let krate = driver::assign_node_ids(&sess, krate);
- let mut hir_forest = hir_map::Forest::new(lower_crate(&krate));
+ let lcx = LoweringContext::new(&sess, Some(&krate));
+ let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate));
let arenas = ty::CtxtArenas::new();
let ast_map = driver::make_map(&sess, &mut hir_forest);
let krate = ast_map.krate();
// run just enough stuff to build a tcx:
- let lang_items = lang_items::collect_language_items(krate, &sess);
+ let lang_items = lang_items::collect_language_items(&sess, &ast_map);
let resolve::CrateMap { def_map, freevars, .. } =
resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No);
let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
let region_map = region::resolve_crate(&sess, krate);
- ty::ctxt::create_and_enter(sess,
+ ty::ctxt::create_and_enter(&sess,
&arenas,
def_map,
named_region_map,
-> Option<ast::NodeId> {
assert!(idx < names.len());
for item in &m.items {
- if item.ident.to_string() == names[idx] {
+ if item.name.to_string() == names[idx] {
return search(this, &**item, idx+1, names);
}
}
{
let name = token::intern(name);
ty::ReEarlyBound(ty::EarlyBoundRegion {
- param_id: ast::DUMMY_NODE_ID,
+ def_id: self.infcx.tcx.map.local_def_id(ast::DUMMY_NODE_ID),
space: space,
index: index,
name: name
self.tcx().types.isize)
}
+ pub fn t_rptr_empty(&self) -> Ty<'tcx> {
+ self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty),
+ self.tcx().types.isize)
+ }
+
pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
infer::TypeTrace::dummy(self.tcx())
}
#[test]
fn lub_returning_scope() {
- test_env(EMPTY_SOURCE_STR,
- errors(&["cannot infer an appropriate lifetime"]), |env| {
- env.create_simple_region_hierarchy();
- let t_rptr_scope10 = env.t_rptr_scope(10);
- let t_rptr_scope11 = env.t_rptr_scope(11);
-
- // this should generate an error when regions are resolved
- env.make_lub_ty(env.t_fn(&[], t_rptr_scope10),
- env.t_fn(&[], t_rptr_scope11));
- })
+ test_env(EMPTY_SOURCE_STR, errors(&[]), |env| {
+ env.create_simple_region_hierarchy();
+ let t_rptr_scope10 = env.t_rptr_scope(10);
+ let t_rptr_scope11 = env.t_rptr_scope(11);
+ let t_rptr_empty = env.t_rptr_empty();
+ env.check_lub(env.t_fn(&[t_rptr_scope10], env.tcx().types.isize),
+ env.t_fn(&[t_rptr_scope11], env.tcx().types.isize),
+ env.t_fn(&[t_rptr_empty], env.tcx().types.isize));
+ });
}
#[test]
+++ /dev/null
-// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Functions dealing with attributes and meta items
-
-pub use self::StabilityLevel::*;
-pub use self::ReprAttr::*;
-pub use self::IntType::*;
-
-use hir;
-use hir::{AttrId, Attribute, Attribute_, MetaItem, MetaWord, MetaNameValue, MetaList};
-use lowering::{lower_attr_style, unlower_attribute};
-use syntax::codemap::{Span, Spanned, spanned, dummy_spanned};
-use syntax::codemap::BytePos;
-use syntax::diagnostic::SpanHandler;
-use syntax::attr as syntax_attr;
-use syntax::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
-use syntax::parse::token::{InternedString, intern_and_get_ident};
-use syntax::parse::token;
-use syntax::ptr::P;
-
-use std::cell::Cell;
-use std::collections::HashSet;
-use std::fmt;
-
-pub fn mark_used(attr: &Attribute) {
- syntax_attr::mark_used(&unlower_attribute(attr))
-}
-
-pub trait AttrMetaMethods {
- fn check_name(&self, name: &str) -> bool {
- name == &self.name()[..]
- }
-
- /// Retrieve the name of the meta item, e.g. `foo` in `#[foo]`,
- /// `#[foo="bar"]` and `#[foo(bar)]`
- fn name(&self) -> InternedString;
-
- /// Gets the string value if self is a MetaNameValue variant
- /// containing a string, otherwise None.
- fn value_str(&self) -> Option<InternedString>;
- /// Gets a list of inner meta items from a list MetaItem type.
- fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]>;
-
- fn span(&self) -> Span;
-}
-
-impl AttrMetaMethods for Attribute {
- fn check_name(&self, name: &str) -> bool {
- let matches = name == &self.name()[..];
- if matches {
- syntax_attr::mark_used(&unlower_attribute(self));
- }
- matches
- }
- fn name(&self) -> InternedString { self.meta().name() }
- fn value_str(&self) -> Option<InternedString> {
- self.meta().value_str()
- }
- fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
- self.node.value.meta_item_list()
- }
- fn span(&self) -> Span { self.meta().span }
-}
-
-impl AttrMetaMethods for MetaItem {
- fn name(&self) -> InternedString {
- match self.node {
- MetaWord(ref n) => (*n).clone(),
- MetaNameValue(ref n, _) => (*n).clone(),
- MetaList(ref n, _) => (*n).clone(),
- }
- }
-
- fn value_str(&self) -> Option<InternedString> {
- match self.node {
- MetaNameValue(_, ref v) => {
- match v.node {
- hir::LitStr(ref s, _) => Some((*s).clone()),
- _ => None,
- }
- },
- _ => None
- }
- }
-
- fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
- match self.node {
- MetaList(_, ref l) => Some(&l[..]),
- _ => None
- }
- }
- fn span(&self) -> Span { self.span }
-}
-
-// Annoying, but required to get test_cfg to work
-impl AttrMetaMethods for P<MetaItem> {
- fn name(&self) -> InternedString { (**self).name() }
- fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
- fn meta_item_list<'a>(&'a self) -> Option<&'a [P<MetaItem>]> {
- (**self).meta_item_list()
- }
- fn span(&self) -> Span { (**self).span() }
-}
-
-
-pub trait AttributeMethods {
- fn meta<'a>(&'a self) -> &'a MetaItem;
- fn with_desugared_doc<T, F>(&self, f: F) -> T where
- F: FnOnce(&Attribute) -> T;
-}
-
-impl AttributeMethods for Attribute {
- /// Extract the MetaItem from inside this Attribute.
- fn meta<'a>(&'a self) -> &'a MetaItem {
- &*self.node.value
- }
-
- /// Convert self to a normal #[doc="foo"] comment, if it is a
- /// comment like `///` or `/** */`. (Returns self unchanged for
- /// non-sugared doc attributes.)
- fn with_desugared_doc<T, F>(&self, f: F) -> T where
- F: FnOnce(&Attribute) -> T,
- {
- if self.node.is_sugared_doc {
- let comment = self.value_str().unwrap();
- let meta = mk_name_value_item_str(
- InternedString::new("doc"),
- token::intern_and_get_ident(&strip_doc_comment_decoration(
- &comment)));
- if self.node.style == hir::AttrOuter {
- f(&mk_attr_outer(self.node.id, meta))
- } else {
- f(&mk_attr_inner(self.node.id, meta))
- }
- } else {
- f(self)
- }
- }
-}
-
-/* Constructors */
-
-pub fn mk_name_value_item_str(name: InternedString, value: InternedString)
- -> P<MetaItem> {
- let value_lit = dummy_spanned(hir::LitStr(value, hir::CookedStr));
- mk_name_value_item(name, value_lit)
-}
-
-pub fn mk_name_value_item(name: InternedString, value: hir::Lit)
- -> P<MetaItem> {
- P(dummy_spanned(MetaNameValue(name, value)))
-}
-
-pub fn mk_list_item(name: InternedString, items: Vec<P<MetaItem>>) -> P<MetaItem> {
- P(dummy_spanned(MetaList(name, items)))
-}
-
-pub fn mk_word_item(name: InternedString) -> P<MetaItem> {
- P(dummy_spanned(MetaWord(name)))
-}
-
-thread_local! { static NEXT_ATTR_ID: Cell<usize> = Cell::new(0) }
-
-pub fn mk_attr_id() -> AttrId {
- let id = NEXT_ATTR_ID.with(|slot| {
- let r = slot.get();
- slot.set(r + 1);
- r
- });
- AttrId(id)
-}
-
-/// Returns an inner attribute with the given value.
-pub fn mk_attr_inner(id: AttrId, item: P<MetaItem>) -> Attribute {
- dummy_spanned(Attribute_ {
- id: id,
- style: hir::AttrInner,
- value: item,
- is_sugared_doc: false,
- })
-}
-
-/// Returns an outer attribute with the given value.
-pub fn mk_attr_outer(id: AttrId, item: P<MetaItem>) -> Attribute {
- dummy_spanned(Attribute_ {
- id: id,
- style: hir::AttrOuter,
- value: item,
- is_sugared_doc: false,
- })
-}
-
-pub fn mk_sugared_doc_attr(id: AttrId, text: InternedString, lo: BytePos,
- hi: BytePos)
- -> Attribute {
- let style = lower_attr_style(doc_comment_style(&text));
- let lit = spanned(lo, hi, hir::LitStr(text, hir::CookedStr));
- let attr = Attribute_ {
- id: id,
- style: style,
- value: P(spanned(lo, hi, MetaNameValue(InternedString::new("doc"),
- lit))),
- is_sugared_doc: true
- };
- spanned(lo, hi, attr)
-}
-
-/* Searching */
-/// Check if `needle` occurs in `haystack` by a structural
-/// comparison. This is slightly subtle, and relies on ignoring the
-/// span included in the `==` comparison a plain MetaItem.
-pub fn contains(haystack: &[P<MetaItem>], needle: &MetaItem) -> bool {
- debug!("attr::contains (name={})", needle.name());
- haystack.iter().any(|item| {
- debug!(" testing: {}", item.name());
- item.node == needle.node
- })
-}
-
-pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool {
- debug!("attr::contains_name (name={})", name);
- metas.iter().any(|item| {
- debug!(" testing: {}", item.name());
- item.check_name(name)
- })
-}
-
-pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str)
- -> Option<InternedString> {
- attrs.iter()
- .find(|at| at.check_name(name))
- .and_then(|at| at.value_str())
-}
-
-pub fn last_meta_item_value_str_by_name(items: &[P<MetaItem>], name: &str)
- -> Option<InternedString> {
- items.iter()
- .rev()
- .find(|mi| mi.check_name(name))
- .and_then(|i| i.value_str())
-}
-
-/* Higher-level applications */
-
-pub fn sort_meta_items(items: Vec<P<MetaItem>>) -> Vec<P<MetaItem>> {
- // This is sort of stupid here, but we need to sort by
- // human-readable strings.
- let mut v = items.into_iter()
- .map(|mi| (mi.name(), mi))
- .collect::<Vec<(InternedString, P<MetaItem>)>>();
-
- v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b));
-
- // There doesn't seem to be a more optimal way to do this
- v.into_iter().map(|(_, m)| m.map(|Spanned {node, span}| {
- Spanned {
- node: match node {
- MetaList(n, mis) => MetaList(n, sort_meta_items(mis)),
- _ => node
- },
- span: span
- }
- })).collect()
-}
-
-pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> {
- first_attr_value_str_by_name(attrs, "crate_name")
-}
-
-/// Find the value of #[export_name=*] attribute and check its validity.
-pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option<InternedString> {
- attrs.iter().fold(None, |ia,attr| {
- if attr.check_name("export_name") {
- if let s@Some(_) = attr.value_str() {
- s
- } else {
- diag.span_err(attr.span, "export_name attribute has invalid format");
- diag.handler.help("use #[export_name=\"*\"]");
- None
- }
- } else {
- ia
- }
- })
-}
-
-#[derive(Copy, Clone, PartialEq)]
-pub enum InlineAttr {
- None,
- Hint,
- Always,
- Never,
-}
-
-/// Determine what `#[inline]` attribute is present in `attrs`, if any.
-pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
- // FIXME (#2809)---validate the usage of #[inline] and #[inline]
- attrs.iter().fold(InlineAttr::None, |ia,attr| {
- match attr.node.value.node {
- MetaWord(ref n) if *n == "inline" => {
- syntax_attr::mark_used(&unlower_attribute(attr));
- InlineAttr::Hint
- }
- MetaList(ref n, ref items) if *n == "inline" => {
- syntax_attr::mark_used(&unlower_attribute(attr));
- if items.len() != 1 {
- diagnostic.map(|d|{ d.span_err(attr.span, "expected one argument"); });
- InlineAttr::None
- } else if contains_name(&items[..], "always") {
- InlineAttr::Always
- } else if contains_name(&items[..], "never") {
- InlineAttr::Never
- } else {
- diagnostic.map(|d|{ d.span_err((*items[0]).span, "invalid argument"); });
- InlineAttr::None
- }
- }
- _ => ia
- }
- })
-}
-
-/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
-pub fn requests_inline(attrs: &[Attribute]) -> bool {
- match find_inline_attr(None, attrs) {
- InlineAttr::Hint | InlineAttr::Always => true,
- InlineAttr::None | InlineAttr::Never => false,
- }
-}
-
-/// Represents the #[deprecated] and friends attributes.
-#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
-pub struct Stability {
- pub level: StabilityLevel,
- pub feature: InternedString,
- pub since: Option<InternedString>,
- pub deprecated_since: Option<InternedString>,
- // The reason for the current stability level. If deprecated, the
- // reason for deprecation.
- pub reason: Option<InternedString>,
- // The relevant rust-lang issue
- pub issue: Option<u32>
-}
-
-/// The available stability levels.
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Copy, Eq, Hash)]
-pub enum StabilityLevel {
- Unstable,
- Stable,
-}
-
-impl fmt::Display for StabilityLevel {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(self, f)
- }
-}
-
-fn find_stability_generic<'a,
- AM: AttrMetaMethods,
- I: Iterator<Item=&'a AM>>
- (diagnostic: &SpanHandler, attrs: I, item_sp: Span)
- -> (Option<Stability>, Vec<&'a AM>) {
-
- let mut stab: Option<Stability> = None;
- let mut deprecated: Option<(Option<InternedString>, Option<InternedString>)> = None;
- let mut used_attrs: Vec<&'a AM> = vec![];
-
- 'outer: for attr in attrs {
- let tag = attr.name();
- let tag = &tag[..];
- if tag != "deprecated" && tag != "unstable" && tag != "stable" {
- continue // not a stability level
- }
-
- used_attrs.push(attr);
-
- let (feature, since, reason, issue) = match attr.meta_item_list() {
- Some(metas) => {
- let mut feature = None;
- let mut since = None;
- let mut reason = None;
- let mut issue = None;
- for meta in metas {
- match &*meta.name() {
- "feature" => {
- match meta.value_str() {
- Some(v) => feature = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
- }
- }
- "since" => {
- match meta.value_str() {
- Some(v) => since = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
- }
- }
- "reason" => {
- match meta.value_str() {
- Some(v) => reason = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
- }
- }
- "issue" => {
- match meta.value_str().and_then(|s| s.parse().ok()) {
- Some(v) => issue = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
- }
- }
- _ => {}
- }
- }
- (feature, since, reason, issue)
- }
- None => {
- diagnostic.span_err(attr.span(), "incorrect stability attribute type");
- continue
- }
- };
-
- // Deprecated tags don't require feature names
- if feature == None && tag != "deprecated" {
- diagnostic.span_err(attr.span(), "missing 'feature'");
- }
-
- // Unstable tags don't require a version
- if since == None && tag != "unstable" {
- diagnostic.span_err(attr.span(), "missing 'since'");
- }
-
- if tag == "unstable" || tag == "stable" {
- if stab.is_some() {
- diagnostic.span_err(item_sp, "multiple stability levels");
- }
-
- let level = match tag {
- "unstable" => Unstable,
- "stable" => Stable,
- _ => unreachable!()
- };
-
- stab = Some(Stability {
- level: level,
- feature: feature.unwrap_or(intern_and_get_ident("bogus")),
- since: since,
- deprecated_since: None,
- reason: reason,
- issue: issue,
- });
- } else { // "deprecated"
- if deprecated.is_some() {
- diagnostic.span_err(item_sp, "multiple deprecated attributes");
- }
-
- deprecated = Some((since, reason));
- }
- }
-
- // Merge the deprecation info into the stability info
- if deprecated.is_some() {
- match stab {
- Some(ref mut s) => {
- let (since, reason) = deprecated.unwrap();
- s.deprecated_since = since;
- s.reason = reason;
- }
- None => {
- diagnostic.span_err(item_sp, "deprecated attribute must be paired with \
- either stable or unstable attribute");
- }
- }
- } else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) {
- // non-deprecated unstable items need to point to issues.
- diagnostic.span_err(item_sp,
- "non-deprecated unstable items need to point \
- to an issue with `issue = \"NNN\"`");
- }
-
- (stab, used_attrs)
-}
-
-/// Find the first stability attribute. `None` if none exists.
-pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute],
- item_sp: Span) -> Option<Stability> {
- let (s, used) = find_stability_generic(diagnostic, attrs.iter(), item_sp);
- for used in used { syntax_attr::mark_used(&unlower_attribute(used)) }
- return s;
-}
-
-pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
- let mut set = HashSet::new();
- for meta in metas {
- let name = meta.name();
-
- if !set.insert(name.clone()) {
- panic!(diagnostic.span_fatal(meta.span,
- &format!("duplicate meta item `{}`", name)));
- }
- }
-}
-
-
-/// Parse #[repr(...)] forms.
-///
-/// Valid repr contents: any of the primitive integral type names (see
-/// `int_type_of_word`, below) to specify enum discriminant type; `C`, to use
-/// the same discriminant size that the corresponding C enum would or C
-/// structure layout, and `packed` to remove padding.
-pub fn find_repr_attrs(diagnostic: &SpanHandler, attr: &Attribute) -> Vec<ReprAttr> {
- let mut acc = Vec::new();
- match attr.node.value.node {
- hir::MetaList(ref s, ref items) if *s == "repr" => {
- syntax_attr::mark_used(&unlower_attribute(attr));
- for item in items {
- match item.node {
- hir::MetaWord(ref word) => {
- let hint = match &word[..] {
- // Can't use "extern" because it's not a lexical identifier.
- "C" => Some(ReprExtern),
- "packed" => Some(ReprPacked),
- "simd" => Some(ReprSimd),
- _ => match int_type_of_word(&word) {
- Some(ity) => Some(ReprInt(item.span, ity)),
- None => {
- // Not a word we recognize
- diagnostic.span_err(item.span,
- "unrecognized representation hint");
- None
- }
- }
- };
-
- match hint {
- Some(h) => acc.push(h),
- None => { }
- }
- }
- // Not a word:
- _ => diagnostic.span_err(item.span, "unrecognized enum representation hint")
- }
- }
- }
- // Not a "repr" hint: ignore.
- _ => { }
- }
- acc
-}
-
-fn int_type_of_word(s: &str) -> Option<IntType> {
- match s {
- "i8" => Some(SignedInt(hir::TyI8)),
- "u8" => Some(UnsignedInt(hir::TyU8)),
- "i16" => Some(SignedInt(hir::TyI16)),
- "u16" => Some(UnsignedInt(hir::TyU16)),
- "i32" => Some(SignedInt(hir::TyI32)),
- "u32" => Some(UnsignedInt(hir::TyU32)),
- "i64" => Some(SignedInt(hir::TyI64)),
- "u64" => Some(UnsignedInt(hir::TyU64)),
- "isize" => Some(SignedInt(hir::TyIs)),
- "usize" => Some(UnsignedInt(hir::TyUs)),
- _ => None
- }
-}
-
-#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
-pub enum ReprAttr {
- ReprAny,
- ReprInt(Span, IntType),
- ReprExtern,
- ReprPacked,
- ReprSimd,
-}
-
-impl ReprAttr {
- pub fn is_ffi_safe(&self) -> bool {
- match *self {
- ReprAny => false,
- ReprInt(_sp, ity) => ity.is_ffi_safe(),
- ReprExtern => true,
- ReprPacked => false,
- ReprSimd => true,
- }
- }
-}
-
-#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
-pub enum IntType {
- SignedInt(hir::IntTy),
- UnsignedInt(hir::UintTy)
-}
-
-impl IntType {
- #[inline]
- pub fn is_signed(self) -> bool {
- match self {
- SignedInt(..) => true,
- UnsignedInt(..) => false
- }
- }
- fn is_ffi_safe(self) -> bool {
- match self {
- SignedInt(hir::TyI8) | UnsignedInt(hir::TyU8) |
- SignedInt(hir::TyI16) | UnsignedInt(hir::TyU16) |
- SignedInt(hir::TyI32) | UnsignedInt(hir::TyU32) |
- SignedInt(hir::TyI64) | UnsignedInt(hir::TyU64) => true,
- SignedInt(hir::TyIs) | UnsignedInt(hir::TyUs) => false
- }
- }
-}
//! and returns a piece of the same type.
use hir::*;
-use syntax::ast::{Ident, NodeId, DUMMY_NODE_ID};
+use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, Attribute, Attribute_, MetaItem};
+use syntax::ast::{MetaWord, MetaList, MetaNameValue};
use hir;
use syntax::codemap::{respan, Span, Spanned};
use syntax::owned_slice::OwnedSlice;
}
impl<T> MoveMap<T> for Vec<T> {
- fn move_map<F>(mut self, mut f: F) -> Vec<T> where F: FnMut(T) -> T {
+ fn move_map<F>(mut self, mut f: F) -> Vec<T>
+ where F: FnMut(T) -> T
+ {
for p in &mut self {
unsafe {
// FIXME(#5016) this shouldn't need to zero to be safe.
}
impl<T> MoveMap<T> for OwnedSlice<T> {
- fn move_map<F>(self, f: F) -> OwnedSlice<T> where F: FnMut(T) -> T {
+ fn move_map<F>(self, f: F) -> OwnedSlice<T>
+ where F: FnMut(T) -> T
+ {
OwnedSlice::from_vec(self.into_vec().move_map(f))
}
}
noop_fold_variant(v, self)
}
+ fn fold_name(&mut self, n: Name) -> Name {
+ noop_fold_name(n, self)
+ }
+
fn fold_ident(&mut self, i: Ident) -> Ident {
noop_fold_ident(i, self)
}
noop_fold_path_parameters(p, self)
}
- fn fold_angle_bracketed_parameter_data(&mut self, p: AngleBracketedParameterData)
- -> AngleBracketedParameterData
- {
+ fn fold_angle_bracketed_parameter_data(&mut self,
+ p: AngleBracketedParameterData)
+ -> AngleBracketedParameterData {
noop_fold_angle_bracketed_parameter_data(p, self)
}
- fn fold_parenthesized_parameter_data(&mut self, p: ParenthesizedParameterData)
- -> ParenthesizedParameterData
- {
+ fn fold_parenthesized_parameter_data(&mut self,
+ p: ParenthesizedParameterData)
+ -> ParenthesizedParameterData {
noop_fold_parenthesized_parameter_data(p, self)
}
noop_fold_poly_trait_ref(p, self)
}
- fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> {
- noop_fold_struct_def(struct_def, self)
+ fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData {
+ noop_fold_variant_data(vdata, self)
}
fn fold_lifetimes(&mut self, lts: Vec<Lifetime>) -> Vec<Lifetime> {
noop_fold_opt_lifetime(o_lt, self)
}
- fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg {
- noop_fold_variant_arg(va, self)
- }
-
- fn fold_opt_bounds(&mut self, b: Option<OwnedSlice<TyParamBound>>)
+ fn fold_opt_bounds(&mut self,
+ b: Option<OwnedSlice<TyParamBound>>)
-> Option<OwnedSlice<TyParamBound>> {
noop_fold_opt_bounds(b, self)
}
- fn fold_bounds(&mut self, b: OwnedSlice<TyParamBound>)
- -> OwnedSlice<TyParamBound> {
+ fn fold_bounds(&mut self, b: OwnedSlice<TyParamBound>) -> OwnedSlice<TyParamBound> {
noop_fold_bounds(b, self)
}
noop_fold_field(field, self)
}
- fn fold_where_clause(&mut self, where_clause: WhereClause)
- -> WhereClause {
+ fn fold_where_clause(&mut self, where_clause: WhereClause) -> WhereClause {
noop_fold_where_clause(where_clause, self)
}
- fn fold_where_predicate(&mut self, where_predicate: WherePredicate)
- -> WherePredicate {
+ fn fold_where_predicate(&mut self, where_predicate: WherePredicate) -> WherePredicate {
noop_fold_where_predicate(where_predicate, self)
}
}
}
-pub fn noop_fold_meta_items<T: Folder>(meta_items: Vec<P<MetaItem>>, fld: &mut T)
+pub fn noop_fold_meta_items<T: Folder>(meta_items: Vec<P<MetaItem>>,
+ fld: &mut T)
-> Vec<P<MetaItem>> {
meta_items.move_map(|x| fld.fold_meta_item(x))
}
pub fn noop_fold_view_path<T: Folder>(view_path: P<ViewPath>, fld: &mut T) -> P<ViewPath> {
- view_path.map(|Spanned {node, span}| Spanned {
- node: match node {
- ViewPathSimple(ident, path) => {
- ViewPathSimple(ident, fld.fold_path(path))
- }
- ViewPathGlob(path) => {
- ViewPathGlob(fld.fold_path(path))
- }
- ViewPathList(path, path_list_idents) => {
- ViewPathList(fld.fold_path(path),
- path_list_idents.move_map(|path_list_ident| {
- Spanned {
- node: match path_list_ident.node {
- PathListIdent { id, name, rename } =>
- PathListIdent {
- id: fld.new_id(id),
- name: name,
- rename: rename,
- },
- PathListMod { id, rename } =>
- PathListMod {
- id: fld.new_id(id),
- rename: rename,
- }
- },
- span: fld.new_span(path_list_ident.span)
- }
- }))
- }
- },
- span: fld.new_span(span)
+ view_path.map(|Spanned { node, span }| {
+ Spanned {
+ node: match node {
+ ViewPathSimple(name, path) => {
+ ViewPathSimple(name, fld.fold_path(path))
+ }
+ ViewPathGlob(path) => {
+ ViewPathGlob(fld.fold_path(path))
+ }
+ ViewPathList(path, path_list_idents) => {
+ ViewPathList(fld.fold_path(path),
+ path_list_idents.move_map(|path_list_ident| {
+ Spanned {
+ node: match path_list_ident.node {
+ PathListIdent { id, name, rename } => PathListIdent {
+ id: fld.new_id(id),
+ name: name,
+ rename: rename,
+ },
+ PathListMod { id, rename } => PathListMod {
+ id: fld.new_id(id),
+ rename: rename,
+ },
+ },
+ span: fld.new_span(path_list_ident.span),
+ }
+ }))
+ }
+ },
+ span: fld.new_span(span),
+ }
})
}
attrs.into_iter().flat_map(|x| fld.fold_attribute(x)).collect()
}
-pub fn noop_fold_arm<T: Folder>(Arm {attrs, pats, guard, body}: Arm, fld: &mut T) -> Arm {
+pub fn noop_fold_arm<T: Folder>(Arm { attrs, pats, guard, body }: Arm, fld: &mut T) -> Arm {
Arm {
attrs: fold_attrs(attrs, fld),
pats: pats.move_map(|x| fld.fold_pat(x)),
}
pub fn noop_fold_decl<T: Folder>(d: P<Decl>, fld: &mut T) -> SmallVector<P<Decl>> {
- d.and_then(|Spanned {node, span}| match node {
- DeclLocal(l) => SmallVector::one(P(Spanned {
- node: DeclLocal(fld.fold_local(l)),
- span: fld.new_span(span)
- })),
- DeclItem(it) => fld.fold_item(it).into_iter().map(|i| P(Spanned {
- node: DeclItem(i),
- span: fld.new_span(span)
- })).collect()
+ d.and_then(|Spanned { node, span }| {
+ match node {
+ DeclLocal(l) => SmallVector::one(P(Spanned {
+ node: DeclLocal(fld.fold_local(l)),
+ span: fld.new_span(span),
+ })),
+ DeclItem(it) => fld.fold_item(it)
+ .into_iter()
+ .map(|i| {
+ P(Spanned {
+ node: DeclItem(i),
+ span: fld.new_span(span),
+ })
+ })
+ .collect(),
+ }
})
}
pub fn noop_fold_ty_binding<T: Folder>(b: P<TypeBinding>, fld: &mut T) -> P<TypeBinding> {
- b.map(|TypeBinding { id, ident, ty, span }| TypeBinding {
- id: fld.new_id(id),
- ident: ident,
- ty: fld.fold_ty(ty),
- span: fld.new_span(span),
+ b.map(|TypeBinding { id, name, ty, span }| {
+ TypeBinding {
+ id: fld.new_id(id),
+ name: name,
+ ty: fld.fold_ty(ty),
+ span: fld.new_span(span),
+ }
})
}
pub fn noop_fold_ty<T: Folder>(t: P<Ty>, fld: &mut T) -> P<Ty> {
- t.map(|Ty {id, node, span}| Ty {
- id: fld.new_id(id),
- node: match node {
- TyInfer => node,
- TyVec(ty) => TyVec(fld.fold_ty(ty)),
- TyPtr(mt) => TyPtr(fld.fold_mt(mt)),
- TyRptr(region, mt) => {
- TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
- }
- TyBareFn(f) => {
- TyBareFn(f.map(|BareFnTy {lifetimes, unsafety, abi, decl}| BareFnTy {
- lifetimes: fld.fold_lifetime_defs(lifetimes),
- unsafety: unsafety,
- abi: abi,
- decl: fld.fold_fn_decl(decl)
- }))
- }
- TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
- TyParen(ty) => TyParen(fld.fold_ty(ty)),
- TyPath(qself, path) => {
- let qself = qself.map(|QSelf { ty, position }| {
- QSelf {
- ty: fld.fold_ty(ty),
- position: position
- }
- });
- TyPath(qself, fld.fold_path(path))
- }
- TyObjectSum(ty, bounds) => {
- TyObjectSum(fld.fold_ty(ty),
- fld.fold_bounds(bounds))
- }
- TyFixedLengthVec(ty, e) => {
- TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
- }
- TyTypeof(expr) => {
- TyTypeof(fld.fold_expr(expr))
- }
- TyPolyTraitRef(bounds) => {
- TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
- }
- },
- span: fld.new_span(span)
+ t.map(|Ty { id, node, span }| {
+ Ty {
+ id: fld.new_id(id),
+ node: match node {
+ TyInfer => node,
+ TyVec(ty) => TyVec(fld.fold_ty(ty)),
+ TyPtr(mt) => TyPtr(fld.fold_mt(mt)),
+ TyRptr(region, mt) => {
+ TyRptr(fld.fold_opt_lifetime(region), fld.fold_mt(mt))
+ }
+ TyBareFn(f) => {
+ TyBareFn(f.map(|BareFnTy { lifetimes, unsafety, abi, decl }| {
+ BareFnTy {
+ lifetimes: fld.fold_lifetime_defs(lifetimes),
+ unsafety: unsafety,
+ abi: abi,
+ decl: fld.fold_fn_decl(decl),
+ }
+ }))
+ }
+ TyTup(tys) => TyTup(tys.move_map(|ty| fld.fold_ty(ty))),
+ TyParen(ty) => TyParen(fld.fold_ty(ty)),
+ TyPath(qself, path) => {
+ let qself = qself.map(|QSelf { ty, position }| {
+ QSelf {
+ ty: fld.fold_ty(ty),
+ position: position,
+ }
+ });
+ TyPath(qself, fld.fold_path(path))
+ }
+ TyObjectSum(ty, bounds) => {
+ TyObjectSum(fld.fold_ty(ty), fld.fold_bounds(bounds))
+ }
+ TyFixedLengthVec(ty, e) => {
+ TyFixedLengthVec(fld.fold_ty(ty), fld.fold_expr(e))
+ }
+ TyTypeof(expr) => {
+ TyTypeof(fld.fold_expr(expr))
+ }
+ TyPolyTraitRef(bounds) => {
+ TyPolyTraitRef(bounds.move_map(|b| fld.fold_ty_param_bound(b)))
+ }
+ },
+ span: fld.new_span(span),
+ }
})
}
-pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod {abi, items}: ForeignMod,
- fld: &mut T) -> ForeignMod {
+pub fn noop_fold_foreign_mod<T: Folder>(ForeignMod { abi, items }: ForeignMod,
+ fld: &mut T)
+ -> ForeignMod {
ForeignMod {
abi: abi,
items: items.move_map(|x| fld.fold_foreign_item(x)),
}
pub fn noop_fold_variant<T: Folder>(v: P<Variant>, fld: &mut T) -> P<Variant> {
- v.map(|Spanned {node: Variant_ {id, name, attrs, kind, disr_expr, vis}, span}| Spanned {
+ v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned {
node: Variant_ {
- id: fld.new_id(id),
name: name,
attrs: fold_attrs(attrs, fld),
- kind: match kind {
- TupleVariantKind(variant_args) => {
- TupleVariantKind(variant_args.move_map(|x|
- fld.fold_variant_arg(x)))
- }
- StructVariantKind(struct_def) => {
- StructVariantKind(fld.fold_struct_def(struct_def))
- }
- },
+ data: fld.fold_variant_data(data),
disr_expr: disr_expr.map(|e| fld.fold_expr(e)),
- vis: vis,
},
span: fld.new_span(span),
})
}
+pub fn noop_fold_name<T: Folder>(n: Name, _: &mut T) -> Name {
+ n
+}
+
pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident {
i
}
i
}
-pub fn noop_fold_path<T: Folder>(Path {global, segments, span}: Path, fld: &mut T) -> Path {
+pub fn noop_fold_path<T: Folder>(Path { global, segments, span }: Path, fld: &mut T) -> Path {
Path {
global: global,
- segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment {
- identifier: fld.fold_ident(identifier),
- parameters: fld.fold_path_parameters(parameters),
+ segments: segments.move_map(|PathSegment { identifier, parameters }| {
+ PathSegment {
+ identifier: fld.fold_ident(identifier),
+ parameters: fld.fold_path_parameters(parameters),
+ }
}),
- span: fld.new_span(span)
+ span: fld.new_span(span),
}
}
-pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters, fld: &mut T)
- -> PathParameters
-{
+pub fn noop_fold_path_parameters<T: Folder>(path_parameters: PathParameters,
+ fld: &mut T)
+ -> PathParameters {
match path_parameters {
AngleBracketedParameters(data) =>
AngleBracketedParameters(fld.fold_angle_bracketed_parameter_data(data)),
pub fn noop_fold_angle_bracketed_parameter_data<T: Folder>(data: AngleBracketedParameterData,
fld: &mut T)
- -> AngleBracketedParameterData
-{
+ -> AngleBracketedParameterData {
let AngleBracketedParameterData { lifetimes, types, bindings } = data;
- AngleBracketedParameterData { lifetimes: fld.fold_lifetimes(lifetimes),
- types: types.move_map(|ty| fld.fold_ty(ty)),
- bindings: bindings.move_map(|b| fld.fold_ty_binding(b)) }
+ AngleBracketedParameterData {
+ lifetimes: fld.fold_lifetimes(lifetimes),
+ types: types.move_map(|ty| fld.fold_ty(ty)),
+ bindings: bindings.move_map(|b| fld.fold_ty_binding(b)),
+ }
}
pub fn noop_fold_parenthesized_parameter_data<T: Folder>(data: ParenthesizedParameterData,
fld: &mut T)
- -> ParenthesizedParameterData
-{
+ -> ParenthesizedParameterData {
let ParenthesizedParameterData { inputs, output, span } = data;
- ParenthesizedParameterData { inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
- output: output.map(|ty| fld.fold_ty(ty)),
- span: fld.new_span(span) }
+ ParenthesizedParameterData {
+ inputs: inputs.move_map(|ty| fld.fold_ty(ty)),
+ output: output.map(|ty| fld.fold_ty(ty)),
+ span: fld.new_span(span),
+ }
}
pub fn noop_fold_local<T: Folder>(l: P<Local>, fld: &mut T) -> P<Local> {
- l.map(|Local {id, pat, ty, init, span}| Local {
- id: fld.new_id(id),
- ty: ty.map(|t| fld.fold_ty(t)),
- pat: fld.fold_pat(pat),
- init: init.map(|e| fld.fold_expr(e)),
- span: fld.new_span(span)
+ l.map(|Local { id, pat, ty, init, span }| {
+ Local {
+ id: fld.new_id(id),
+ ty: ty.map(|t| fld.fold_ty(t)),
+ pat: fld.fold_pat(pat),
+ init: init.map(|e| fld.fold_expr(e)),
+ span: fld.new_span(span),
+ }
})
}
id: id,
style: style,
value: fld.fold_meta_item(value),
- is_sugared_doc: is_sugared_doc
+ is_sugared_doc: is_sugared_doc,
},
- span: fld.new_span(span)
+ span: fld.new_span(span),
})
}
-pub fn noop_fold_explicit_self_underscore<T: Folder>(es: ExplicitSelf_, fld: &mut T)
+pub fn noop_fold_explicit_self_underscore<T: Folder>(es: ExplicitSelf_,
+ fld: &mut T)
-> ExplicitSelf_ {
match es {
SelfStatic | SelfValue(_) => es,
- SelfRegion(lifetime, m, ident) => {
- SelfRegion(fld.fold_opt_lifetime(lifetime), m, ident)
+ SelfRegion(lifetime, m, name) => {
+ SelfRegion(fld.fold_opt_lifetime(lifetime), m, name)
}
- SelfExplicit(typ, ident) => {
- SelfExplicit(fld.fold_ty(typ), ident)
+ SelfExplicit(typ, name) => {
+ SelfExplicit(fld.fold_ty(typ), name)
}
}
}
-pub fn noop_fold_explicit_self<T: Folder>(Spanned {span, node}: ExplicitSelf, fld: &mut T)
+pub fn noop_fold_explicit_self<T: Folder>(Spanned { span, node }: ExplicitSelf,
+ fld: &mut T)
-> ExplicitSelf {
Spanned {
node: fld.fold_explicit_self_underscore(node),
- span: fld.new_span(span)
+ span: fld.new_span(span),
}
}
pub fn noop_fold_meta_item<T: Folder>(mi: P<MetaItem>, fld: &mut T) -> P<MetaItem> {
- mi.map(|Spanned {node, span}| Spanned {
- node: match node {
- MetaWord(id) => MetaWord(id),
- MetaList(id, mis) => {
- MetaList(id, mis.move_map(|e| fld.fold_meta_item(e)))
- }
- MetaNameValue(id, s) => MetaNameValue(id, s)
- },
- span: fld.new_span(span)
+ mi.map(|Spanned { node, span }| {
+ Spanned {
+ node: match node {
+ MetaWord(id) => MetaWord(id),
+ MetaList(id, mis) => {
+ MetaList(id, mis.move_map(|e| fld.fold_meta_item(e)))
+ }
+ MetaNameValue(id, s) => MetaNameValue(id, s),
+ },
+ span: fld.new_span(span),
+ }
})
}
-pub fn noop_fold_arg<T: Folder>(Arg {id, pat, ty}: Arg, fld: &mut T) -> Arg {
+pub fn noop_fold_arg<T: Folder>(Arg { id, pat, ty }: Arg, fld: &mut T) -> Arg {
Arg {
id: fld.new_id(id),
pat: fld.fold_pat(pat),
- ty: fld.fold_ty(ty)
+ ty: fld.fold_ty(ty),
}
}
pub fn noop_fold_fn_decl<T: Folder>(decl: P<FnDecl>, fld: &mut T) -> P<FnDecl> {
- decl.map(|FnDecl {inputs, output, variadic}| FnDecl {
- inputs: inputs.move_map(|x| fld.fold_arg(x)),
- output: match output {
- Return(ty) => Return(fld.fold_ty(ty)),
- DefaultReturn(span) => DefaultReturn(span),
- NoReturn(span) => NoReturn(span)
- },
- variadic: variadic
+ decl.map(|FnDecl { inputs, output, variadic }| {
+ FnDecl {
+ inputs: inputs.move_map(|x| fld.fold_arg(x)),
+ output: match output {
+ Return(ty) => Return(fld.fold_ty(ty)),
+ DefaultReturn(span) => DefaultReturn(span),
+ NoReturn(span) => NoReturn(span),
+ },
+ variadic: variadic,
+ }
})
}
-pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T)
- -> TyParamBound
- where T: Folder {
+pub fn noop_fold_ty_param_bound<T>(tpb: TyParamBound, fld: &mut T) -> TyParamBound
+ where T: Folder
+{
match tpb {
TraitTyParamBound(ty, modifier) => TraitTyParamBound(fld.fold_poly_trait_ref(ty), modifier),
RegionTyParamBound(lifetime) => RegionTyParamBound(fld.fold_lifetime(lifetime)),
}
pub fn noop_fold_ty_param<T: Folder>(tp: TyParam, fld: &mut T) -> TyParam {
- let TyParam {id, ident, bounds, default, span} = tp;
+ let TyParam {id, name, bounds, default, span} = tp;
TyParam {
id: fld.new_id(id),
- ident: ident,
+ name: name,
bounds: fld.fold_bounds(bounds),
default: default.map(|x| fld.fold_ty(x)),
- span: span
+ span: span,
}
}
-pub fn noop_fold_ty_params<T: Folder>(tps: OwnedSlice<TyParam>, fld: &mut T)
+pub fn noop_fold_ty_params<T: Folder>(tps: OwnedSlice<TyParam>,
+ fld: &mut T)
-> OwnedSlice<TyParam> {
tps.move_map(|tp| fld.fold_ty_param(tp))
}
Lifetime {
id: fld.new_id(l.id),
name: l.name,
- span: fld.new_span(l.span)
+ span: fld.new_span(l.span),
}
}
-pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T)
- -> LifetimeDef {
+pub fn noop_fold_lifetime_def<T: Folder>(l: LifetimeDef, fld: &mut T) -> LifetimeDef {
LifetimeDef {
lifetime: fld.fold_lifetime(l.lifetime),
bounds: fld.fold_lifetimes(l.bounds),
lts.move_map(|l| fld.fold_lifetime(l))
}
-pub fn noop_fold_lifetime_defs<T: Folder>(lts: Vec<LifetimeDef>, fld: &mut T)
- -> Vec<LifetimeDef> {
+pub fn noop_fold_lifetime_defs<T: Folder>(lts: Vec<LifetimeDef>, fld: &mut T) -> Vec<LifetimeDef> {
lts.move_map(|l| fld.fold_lifetime_def(l))
}
-pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T)
- -> Option<Lifetime> {
+pub fn noop_fold_opt_lifetime<T: Folder>(o_lt: Option<Lifetime>, fld: &mut T) -> Option<Lifetime> {
o_lt.map(|lt| fld.fold_lifetime(lt))
}
-pub fn noop_fold_generics<T: Folder>(Generics {ty_params, lifetimes, where_clause}: Generics,
- fld: &mut T) -> Generics {
+pub fn noop_fold_generics<T: Folder>(Generics { ty_params, lifetimes, where_clause }: Generics,
+ fld: &mut T)
+ -> Generics {
Generics {
ty_params: fld.fold_ty_params(ty_params),
lifetimes: fld.fold_lifetime_defs(lifetimes),
}
}
-pub fn noop_fold_where_clause<T: Folder>(
- WhereClause {id, predicates}: WhereClause,
- fld: &mut T)
- -> WhereClause {
+pub fn noop_fold_where_clause<T: Folder>(WhereClause { id, predicates }: WhereClause,
+ fld: &mut T)
+ -> WhereClause {
WhereClause {
id: fld.new_id(id),
- predicates: predicates.move_map(|predicate| {
- fld.fold_where_predicate(predicate)
- })
+ predicates: predicates.move_map(|predicate| fld.fold_where_predicate(predicate)),
}
}
-pub fn noop_fold_where_predicate<T: Folder>(
- pred: WherePredicate,
- fld: &mut T)
- -> WherePredicate {
+pub fn noop_fold_where_predicate<T: Folder>(pred: WherePredicate, fld: &mut T) -> WherePredicate {
match pred {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{bound_lifetimes,
bounded_ty,
bound_lifetimes: fld.fold_lifetime_defs(bound_lifetimes),
bounded_ty: fld.fold_ty(bounded_ty),
bounds: bounds.move_map(|x| fld.fold_ty_param_bound(x)),
- span: fld.new_span(span)
+ span: fld.new_span(span),
})
}
hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{lifetime,
hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
span: fld.new_span(span),
lifetime: fld.fold_lifetime(lifetime),
- bounds: bounds.move_map(|bound| fld.fold_lifetime(bound))
+ bounds: bounds.move_map(|bound| fld.fold_lifetime(bound)),
})
}
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id,
path,
ty,
span}) => {
- hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{
+ hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
id: fld.new_id(id),
path: fld.fold_path(path),
- ty:fld.fold_ty(ty),
- span: fld.new_span(span)
+ ty: fld.fold_ty(ty),
+ span: fld.new_span(span),
})
}
}
}
-pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
- struct_def.map(|StructDef { fields, ctor_id }| StructDef {
- fields: fields.move_map(|f| fld.fold_struct_field(f)),
- ctor_id: ctor_id.map(|cid| fld.new_id(cid)),
- })
+pub fn noop_fold_variant_data<T: Folder>(vdata: VariantData, fld: &mut T) -> VariantData {
+ match vdata {
+ VariantData::Struct(fields, id) => {
+ VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
+ }
+ VariantData::Tuple(fields, id) => {
+ VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)), fld.new_id(id))
+ }
+ VariantData::Unit(id) => VariantData::Unit(fld.new_id(id))
+ }
}
pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
ty: fld.fold_ty(ty),
attrs: fold_attrs(attrs, fld),
},
- span: fld.new_span(span)
+ span: fld.new_span(span),
}
}
-pub fn noop_fold_field<T: Folder>(Field {ident, expr, span}: Field, folder: &mut T) -> Field {
+pub fn noop_fold_field<T: Folder>(Field { name, expr, span }: Field, folder: &mut T) -> Field {
Field {
- ident: respan(ident.span, folder.fold_ident(ident.node)),
+ name: respan(folder.new_span(name.span),
+ folder.fold_name(name.node)),
expr: folder.fold_expr(expr),
- span: folder.new_span(span)
+ span: folder.new_span(span),
}
}
-pub fn noop_fold_mt<T: Folder>(MutTy {ty, mutbl}: MutTy, folder: &mut T) -> MutTy {
+pub fn noop_fold_mt<T: Folder>(MutTy { ty, mutbl }: MutTy, folder: &mut T) -> MutTy {
MutTy {
ty: folder.fold_ty(ty),
mutbl: mutbl,
}
}
-pub fn noop_fold_opt_bounds<T: Folder>(b: Option<OwnedSlice<TyParamBound>>, folder: &mut T)
+pub fn noop_fold_opt_bounds<T: Folder>(b: Option<OwnedSlice<TyParamBound>>,
+ folder: &mut T)
-> Option<OwnedSlice<TyParamBound>> {
b.map(|bounds| folder.fold_bounds(bounds))
}
-fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T)
- -> TyParamBounds {
+fn noop_fold_bounds<T: Folder>(bounds: TyParamBounds, folder: &mut T) -> TyParamBounds {
bounds.move_map(|bound| folder.fold_ty_param_bound(bound))
}
-fn noop_fold_variant_arg<T: Folder>(VariantArg {id, ty}: VariantArg, folder: &mut T)
- -> VariantArg {
- VariantArg {
- id: folder.new_id(id),
- ty: folder.fold_ty(ty)
- }
-}
-
pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
- b.map(|Block {id, stmts, expr, rules, span}| Block {
- id: folder.new_id(id),
- stmts: stmts.into_iter().flat_map(|s| folder.fold_stmt(s).into_iter()).collect(),
- expr: expr.map(|x| folder.fold_expr(x)),
- rules: rules,
- span: folder.new_span(span),
+ b.map(|Block { id, stmts, expr, rules, span }| {
+ Block {
+ id: folder.new_id(id),
+ stmts: stmts.into_iter().flat_map(|s| folder.fold_stmt(s).into_iter()).collect(),
+ expr: expr.map(|x| folder.fold_expr(x)),
+ rules: rules,
+ span: folder.new_span(span),
+ }
})
}
ItemConst(folder.fold_ty(t), folder.fold_expr(e))
}
ItemFn(decl, unsafety, constness, abi, generics, body) => {
- ItemFn(
- folder.fold_fn_decl(decl),
- unsafety,
- constness,
- abi,
- folder.fold_generics(generics),
- folder.fold_block(body)
- )
+ ItemFn(folder.fold_fn_decl(decl),
+ unsafety,
+ constness,
+ abi,
+ folder.fold_generics(generics),
+ folder.fold_block(body))
}
ItemMod(m) => ItemMod(folder.fold_mod(m)),
ItemForeignMod(nm) => ItemForeignMod(folder.fold_foreign_mod(nm)),
ItemTy(folder.fold_ty(t), folder.fold_generics(generics))
}
ItemEnum(enum_definition, generics) => {
- ItemEnum(
- hir::EnumDef {
- variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)),
- },
- folder.fold_generics(generics))
+ ItemEnum(hir::EnumDef {
+ variants: enum_definition.variants.move_map(|x| folder.fold_variant(x)),
+ },
+ folder.fold_generics(generics))
}
ItemStruct(struct_def, generics) => {
- let struct_def = folder.fold_struct_def(struct_def);
+ let struct_def = folder.fold_variant_data(struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
ItemDefaultImpl(unsafety, ref trait_ref) => {
- ItemDefaultImpl(unsafety, folder.fold_trait_ref((*trait_ref).clone()))
+ ItemDefaultImpl(unsafety,
+ folder.fold_trait_ref((*trait_ref).clone()))
}
ItemImpl(unsafety, polarity, generics, ifce, ty, impl_items) => {
- let new_impl_items = impl_items.into_iter().flat_map(|item| {
- folder.fold_impl_item(item).into_iter()
- }).collect();
+ let new_impl_items = impl_items.into_iter()
+ .flat_map(|item| {
+ folder.fold_impl_item(item).into_iter()
+ })
+ .collect();
let ifce = match ifce {
None => None,
Some(ref trait_ref) => {
}
ItemTrait(unsafety, generics, bounds, items) => {
let bounds = folder.fold_bounds(bounds);
- let items = items.into_iter().flat_map(|item| {
- folder.fold_trait_item(item).into_iter()
- }).collect();
- ItemTrait(unsafety,
- folder.fold_generics(generics),
- bounds,
- items)
+ let items = items.into_iter()
+ .flat_map(|item| folder.fold_trait_item(item).into_iter())
+ .collect();
+ ItemTrait(unsafety, folder.fold_generics(generics), bounds, items)
}
}
}
-pub fn noop_fold_trait_item<T: Folder>(i: P<TraitItem>, folder: &mut T)
+pub fn noop_fold_trait_item<T: Folder>(i: P<TraitItem>,
+ folder: &mut T)
-> SmallVector<P<TraitItem>> {
- SmallVector::one(i.map(|TraitItem {id, ident, attrs, node, span}| TraitItem {
- id: folder.new_id(id),
- ident: folder.fold_ident(ident),
- attrs: fold_attrs(attrs, folder),
- node: match node {
- ConstTraitItem(ty, default) => {
- ConstTraitItem(folder.fold_ty(ty),
- default.map(|x| folder.fold_expr(x)))
- }
- MethodTraitItem(sig, body) => {
- MethodTraitItem(noop_fold_method_sig(sig, folder),
- body.map(|x| folder.fold_block(x)))
- }
- TypeTraitItem(bounds, default) => {
- TypeTraitItem(folder.fold_bounds(bounds),
- default.map(|x| folder.fold_ty(x)))
- }
- },
- span: folder.new_span(span)
+ SmallVector::one(i.map(|TraitItem { id, name, attrs, node, span }| {
+ TraitItem {
+ id: folder.new_id(id),
+ name: folder.fold_name(name),
+ attrs: fold_attrs(attrs, folder),
+ node: match node {
+ ConstTraitItem(ty, default) => {
+ ConstTraitItem(folder.fold_ty(ty),
+ default.map(|x| folder.fold_expr(x)))
+ }
+ MethodTraitItem(sig, body) => {
+ MethodTraitItem(noop_fold_method_sig(sig, folder),
+ body.map(|x| folder.fold_block(x)))
+ }
+ TypeTraitItem(bounds, default) => {
+ TypeTraitItem(folder.fold_bounds(bounds),
+ default.map(|x| folder.fold_ty(x)))
+ }
+ },
+ span: folder.new_span(span),
+ }
}))
}
-pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T)
- -> SmallVector<P<ImplItem>> {
- SmallVector::one(i.map(|ImplItem {id, ident, attrs, node, vis, span}| ImplItem {
- id: folder.new_id(id),
- ident: folder.fold_ident(ident),
- attrs: fold_attrs(attrs, folder),
- vis: vis,
- node: match node {
- ConstImplItem(ty, expr) => {
- ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr))
- }
- MethodImplItem(sig, body) => {
- MethodImplItem(noop_fold_method_sig(sig, folder),
- folder.fold_block(body))
- }
- TypeImplItem(ty) => TypeImplItem(folder.fold_ty(ty)),
- },
- span: folder.new_span(span)
+pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T) -> SmallVector<P<ImplItem>> {
+ SmallVector::one(i.map(|ImplItem { id, name, attrs, node, vis, span }| {
+ ImplItem {
+ id: folder.new_id(id),
+ name: folder.fold_name(name),
+ attrs: fold_attrs(attrs, folder),
+ vis: vis,
+ node: match node {
+ ConstImplItem(ty, expr) => {
+ ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr))
+ }
+ MethodImplItem(sig, body) => {
+ MethodImplItem(noop_fold_method_sig(sig, folder),
+ folder.fold_block(body))
+ }
+ TypeImplItem(ty) => TypeImplItem(folder.fold_ty(ty)),
+ },
+ span: folder.new_span(span),
+ }
}))
}
-pub fn noop_fold_mod<T: Folder>(Mod {inner, items}: Mod, folder: &mut T) -> Mod {
+pub fn noop_fold_mod<T: Folder>(Mod { inner, items }: Mod, folder: &mut T) -> Mod {
Mod {
inner: folder.new_span(inner),
items: items.into_iter().flat_map(|x| folder.fold_item(x).into_iter()).collect(),
}
}
-pub fn noop_fold_crate<T: Folder>(Crate {module, attrs, config, span, exported_macros}: Crate,
- folder: &mut T) -> Crate {
+pub fn noop_fold_crate<T: Folder>(Crate { module, attrs, config, span, exported_macros }: Crate,
+ folder: &mut T)
+ -> Crate {
let config = folder.fold_meta_items(config);
let mut items = folder.fold_item(P(hir::Item {
- ident: token::special_idents::invalid,
- attrs: attrs,
- id: DUMMY_NODE_ID,
- vis: hir::Public,
- span: span,
- node: hir::ItemMod(module),
- })).into_iter();
+ name: token::special_idents::invalid.name,
+ attrs: attrs,
+ id: DUMMY_NODE_ID,
+ vis: hir::Public,
+ span: span,
+ node: hir::ItemMod(module),
+ }))
+ .into_iter();
let (module, attrs, span) = match items.next() {
Some(item) => {
None => (hir::Mod {
inner: span,
items: vec![],
- }, vec![], span)
+ },
+ vec![],
+ span),
};
Crate {
}
// fold one item into exactly one item
-pub fn noop_fold_item_simple<T: Folder>(Item {id, ident, attrs, node, vis, span}: Item,
- folder: &mut T) -> Item {
+pub fn noop_fold_item_simple<T: Folder>(Item { id, name, attrs, node, vis, span }: Item,
+ folder: &mut T)
+ -> Item {
let id = folder.new_id(id);
let node = folder.fold_item_underscore(node);
// FIXME: we should update the impl_pretty_name, but it uses pretty printing.
Item {
id: id,
- ident: folder.fold_ident(ident),
+ name: folder.fold_name(name),
attrs: fold_attrs(attrs, folder),
node: node,
vis: vis,
- span: folder.new_span(span)
+ span: folder.new_span(span),
}
}
pub fn noop_fold_foreign_item<T: Folder>(ni: P<ForeignItem>, folder: &mut T) -> P<ForeignItem> {
- ni.map(|ForeignItem {id, ident, attrs, node, span, vis}| ForeignItem {
- id: folder.new_id(id),
- ident: folder.fold_ident(ident),
- attrs: fold_attrs(attrs, folder),
- node: match node {
- ForeignItemFn(fdec, generics) => {
- ForeignItemFn(folder.fold_fn_decl(fdec), folder.fold_generics(generics))
- }
- ForeignItemStatic(t, m) => {
- ForeignItemStatic(folder.fold_ty(t), m)
- }
- },
- vis: vis,
- span: folder.new_span(span)
+ ni.map(|ForeignItem { id, name, attrs, node, span, vis }| {
+ ForeignItem {
+ id: folder.new_id(id),
+ name: folder.fold_name(name),
+ attrs: fold_attrs(attrs, folder),
+ node: match node {
+ ForeignItemFn(fdec, generics) => {
+ ForeignItemFn(folder.fold_fn_decl(fdec),
+ folder.fold_generics(generics))
+ }
+ ForeignItemStatic(t, m) => {
+ ForeignItemStatic(folder.fold_ty(t), m)
+ }
+ },
+ vis: vis,
+ span: folder.new_span(span),
+ }
})
}
explicit_self: folder.fold_explicit_self(sig.explicit_self),
unsafety: sig.unsafety,
constness: sig.constness,
- decl: folder.fold_fn_decl(sig.decl)
+ decl: folder.fold_fn_decl(sig.decl),
}
}
pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
- p.map(|Pat {id, node, span}| Pat {
- id: folder.new_id(id),
- node: match node {
- PatWild(k) => PatWild(k),
- PatIdent(binding_mode, pth1, sub) => {
- PatIdent(binding_mode,
- Spanned{span: folder.new_span(pth1.span),
- node: folder.fold_ident(pth1.node)},
- sub.map(|x| folder.fold_pat(x)))
- }
- PatLit(e) => PatLit(folder.fold_expr(e)),
- PatEnum(pth, pats) => {
- PatEnum(folder.fold_path(pth),
- pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
- }
- PatQPath(qself, pth) => {
- let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself};
- PatQPath(qself, folder.fold_path(pth))
- }
- PatStruct(pth, fields, etc) => {
- let pth = folder.fold_path(pth);
- let fs = fields.move_map(|f| {
- Spanned { span: folder.new_span(f.span),
- node: hir::FieldPat {
- ident: f.node.ident,
- pat: folder.fold_pat(f.node.pat),
- is_shorthand: f.node.is_shorthand,
- }}
- });
- PatStruct(pth, fs, etc)
- }
- PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))),
- PatBox(inner) => PatBox(folder.fold_pat(inner)),
- PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl),
- PatRange(e1, e2) => {
- PatRange(folder.fold_expr(e1), folder.fold_expr(e2))
+ p.map(|Pat { id, node, span }| {
+ Pat {
+ id: folder.new_id(id),
+ node: match node {
+ PatWild(k) => PatWild(k),
+ PatIdent(binding_mode, pth1, sub) => {
+ PatIdent(binding_mode,
+ Spanned {
+ span: folder.new_span(pth1.span),
+ node: folder.fold_ident(pth1.node),
+ },
+ sub.map(|x| folder.fold_pat(x)))
+ }
+ PatLit(e) => PatLit(folder.fold_expr(e)),
+ PatEnum(pth, pats) => {
+ PatEnum(folder.fold_path(pth),
+ pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
+ }
+ PatQPath(qself, pth) => {
+ let qself = QSelf { ty: folder.fold_ty(qself.ty), ..qself };
+ PatQPath(qself, folder.fold_path(pth))
+ }
+ PatStruct(pth, fields, etc) => {
+ let pth = folder.fold_path(pth);
+ let fs = fields.move_map(|f| {
+ Spanned {
+ span: folder.new_span(f.span),
+ node: hir::FieldPat {
+ name: f.node.name,
+ pat: folder.fold_pat(f.node.pat),
+ is_shorthand: f.node.is_shorthand,
+ },
+ }
+ });
+ PatStruct(pth, fs, etc)
+ }
+ PatTup(elts) => PatTup(elts.move_map(|x| folder.fold_pat(x))),
+ PatBox(inner) => PatBox(folder.fold_pat(inner)),
+ PatRegion(inner, mutbl) => PatRegion(folder.fold_pat(inner), mutbl),
+ PatRange(e1, e2) => {
+ PatRange(folder.fold_expr(e1), folder.fold_expr(e2))
+ }
+ PatVec(before, slice, after) => {
+ PatVec(before.move_map(|x| folder.fold_pat(x)),
+ slice.map(|x| folder.fold_pat(x)),
+ after.move_map(|x| folder.fold_pat(x)))
+ }
},
- PatVec(before, slice, after) => {
- PatVec(before.move_map(|x| folder.fold_pat(x)),
- slice.map(|x| folder.fold_pat(x)),
- after.move_map(|x| folder.fold_pat(x)))
- }
- },
- span: folder.new_span(span)
+ span: folder.new_span(span),
+ }
})
}
-pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) -> Expr {
+pub fn noop_fold_expr<T: Folder>(Expr { id, node, span }: Expr, folder: &mut T) -> Expr {
Expr {
id: folder.new_id(id),
node: match node {
- ExprBox(p, e) => {
- ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e))
+ ExprBox(e) => {
+ ExprBox(folder.fold_expr(e))
}
ExprVec(exprs) => {
ExprVec(exprs.move_map(|x| folder.fold_expr(x)))
ExprCall(folder.fold_expr(f),
args.move_map(|x| folder.fold_expr(x)))
}
- ExprMethodCall(i, tps, args) => {
- ExprMethodCall(
- respan(folder.new_span(i.span), folder.fold_ident(i.node)),
- tps.move_map(|x| folder.fold_ty(x)),
- args.move_map(|x| folder.fold_expr(x)))
+ ExprMethodCall(name, tps, args) => {
+ ExprMethodCall(respan(folder.new_span(name.span),
+ folder.fold_name(name.node)),
+ tps.move_map(|x| folder.fold_ty(x)),
+ args.move_map(|x| folder.fold_expr(x)))
}
ExprBinary(binop, lhs, rhs) => {
- ExprBinary(binop,
- folder.fold_expr(lhs),
- folder.fold_expr(rhs))
+ ExprBinary(binop, folder.fold_expr(lhs), folder.fold_expr(rhs))
}
ExprUnary(binop, ohs) => {
ExprUnary(binop, folder.fold_expr(ohs))
}
ExprLoop(body, opt_ident) => {
ExprLoop(folder.fold_block(body),
- opt_ident.map(|i| folder.fold_ident(i)))
+ opt_ident.map(|i| folder.fold_ident(i)))
}
ExprMatch(expr, arms, source) => {
ExprMatch(folder.fold_expr(expr),
- arms.move_map(|x| folder.fold_arm(x)),
- source)
+ arms.move_map(|x| folder.fold_arm(x)),
+ source)
}
ExprClosure(capture_clause, decl, body) => {
ExprClosure(capture_clause,
ExprAssign(folder.fold_expr(el), folder.fold_expr(er))
}
ExprAssignOp(op, el, er) => {
- ExprAssignOp(op,
- folder.fold_expr(el),
- folder.fold_expr(er))
+ ExprAssignOp(op, folder.fold_expr(el), folder.fold_expr(er))
}
- ExprField(el, ident) => {
+ ExprField(el, name) => {
ExprField(folder.fold_expr(el),
- respan(folder.new_span(ident.span),
- folder.fold_ident(ident.node)))
+ respan(folder.new_span(name.span),
+ folder.fold_name(name.node)))
}
- ExprTupField(el, ident) => {
+ ExprTupField(el, index) => {
ExprTupField(folder.fold_expr(el),
- respan(folder.new_span(ident.span),
- folder.fold_usize(ident.node)))
+ respan(folder.new_span(index.span),
+ folder.fold_usize(index.node)))
}
ExprIndex(el, er) => {
ExprIndex(folder.fold_expr(el), folder.fold_expr(er))
let qself = qself.map(|QSelf { ty, position }| {
QSelf {
ty: folder.fold_ty(ty),
- position: position
+ position: position,
}
});
ExprPath(qself, folder.fold_path(path))
}
- ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label|
+ ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label| {
respan(folder.new_span(label.span),
- folder.fold_ident(label.node)))
- ),
- ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label|
+ folder.fold_ident(label.node))
+ })),
+ ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label| {
respan(folder.new_span(label.span),
- folder.fold_ident(label.node)))
- ),
+ folder.fold_ident(label.node))
+ })),
ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
ExprInlineAsm(InlineAsm {
inputs,
dialect,
expn_id,
}) => ExprInlineAsm(InlineAsm {
- inputs: inputs.move_map(|(c, input)| {
- (c, folder.fold_expr(input))
- }),
- outputs: outputs.move_map(|(c, out, is_rw)| {
- (c, folder.fold_expr(out), is_rw)
- }),
+ inputs: inputs.move_map(|(c, input)| (c, folder.fold_expr(input))),
+ outputs: outputs.move_map(|(c, out, is_rw)| (c, folder.fold_expr(out), is_rw)),
asm: asm,
asm_str_style: asm_str_style,
clobbers: clobbers,
}),
ExprStruct(path, fields, maybe_expr) => {
ExprStruct(folder.fold_path(path),
- fields.move_map(|x| folder.fold_field(x)),
- maybe_expr.map(|x| folder.fold_expr(x)))
- },
- ExprParen(ex) => ExprParen(folder.fold_expr(ex))
+ fields.move_map(|x| folder.fold_field(x)),
+ maybe_expr.map(|x| folder.fold_expr(x)))
+ }
},
- span: folder.new_span(span)
+ span: folder.new_span(span),
}
}
-pub fn noop_fold_stmt<T: Folder>(Spanned {node, span}: Stmt, folder: &mut T)
+pub fn noop_fold_stmt<T: Folder>(Spanned { node, span }: Stmt,
+ folder: &mut T)
-> SmallVector<P<Stmt>> {
let span = folder.new_span(span);
match node {
StmtDecl(d, id) => {
let id = folder.new_id(id);
- folder.fold_decl(d).into_iter().map(|d| P(Spanned {
- node: StmtDecl(d, id),
- span: span
- })).collect()
+ folder.fold_decl(d)
+ .into_iter()
+ .map(|d| {
+ P(Spanned {
+ node: StmtDecl(d, id),
+ span: span,
+ })
+ })
+ .collect()
}
StmtExpr(e, id) => {
let id = folder.new_id(id);
SmallVector::one(P(Spanned {
node: StmtExpr(folder.fold_expr(e), id),
- span: span
+ span: span,
}))
}
StmtSemi(e, id) => {
let id = folder.new_id(id);
SmallVector::one(P(Spanned {
node: StmtSemi(folder.fold_expr(e), id),
- span: span
+ span: span,
}))
}
}
// The Rust HIR.
-pub use self::AsmDialect::*;
-pub use self::AttrStyle::*;
pub use self::BindingMode::*;
pub use self::BinOp_::*;
pub use self::BlockCheckMode::*;
pub use self::Decl_::*;
pub use self::ExplicitSelf_::*;
pub use self::Expr_::*;
-pub use self::FloatTy::*;
pub use self::FunctionRetTy::*;
pub use self::ForeignItem_::*;
pub use self::ImplItem_::*;
-pub use self::IntTy::*;
pub use self::Item_::*;
-pub use self::Lit_::*;
-pub use self::LitIntType::*;
-pub use self::MetaItem_::*;
pub use self::Mutability::*;
pub use self::Pat_::*;
pub use self::PathListItem_::*;
pub use self::PatWildKind::*;
pub use self::PrimTy::*;
-pub use self::Sign::*;
pub use self::Stmt_::*;
-pub use self::StrStyle::*;
pub use self::StructFieldKind::*;
pub use self::TraitItem_::*;
pub use self::Ty_::*;
pub use self::TyParamBound::*;
-pub use self::UintTy::*;
pub use self::UnOp::*;
pub use self::UnsafeSource::*;
-pub use self::VariantKind::*;
pub use self::ViewPath_::*;
pub use self::Visibility::*;
pub use self::PathParameters::*;
use syntax::codemap::{self, Span, Spanned, DUMMY_SP, ExpnId};
use syntax::abi::Abi;
-use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree};
+use syntax::ast::{Name, Ident, NodeId, DUMMY_NODE_ID, TokenTree, AsmDialect};
+use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, CrateConfig};
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use util;
use std::fmt;
-use std::rc::Rc;
use serialize::{Encodable, Encoder, Decoder};
-
-/// Function name (not all functions have names)
-pub type FnIdent = Option<Ident>;
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime {
pub id: NodeId,
pub span: Span,
- pub name: Name
+ pub name: Name,
}
impl fmt::Debug for Lifetime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "lifetime({}: {})", self.id, pprust::lifetime_to_string(self))
+ write!(f,
+ "lifetime({}: {})",
+ self.id,
+ pprust::lifetime_to_string(self))
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct LifetimeDef {
pub lifetime: Lifetime,
- pub bounds: Vec<Lifetime>
+ pub bounds: Vec<Lifetime>,
}
/// A "Path" is essentially Rust's notion of a name; for instance:
data.types.iter().collect()
}
ParenthesizedParameters(ref data) => {
- data.inputs.iter()
+ data.inputs
+ .iter()
.chain(data.output.iter())
.collect()
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum TyParamBound {
TraitTyParamBound(PolyTraitRef, TraitBoundModifier),
- RegionTyParamBound(Lifetime)
+ RegionTyParamBound(Lifetime),
}
/// A modifier on a bound, currently this is only used for `?Sized`, where the
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TyParam {
- pub ident: Ident,
+ pub name: Name,
pub id: NodeId,
pub bounds: TyParamBounds,
pub default: Option<P<Ty>>,
- pub span: Span
+ pub span: Span,
}
/// Represents lifetimes and type parameters attached to a declaration
/// A lifetime predicate, e.g. `'a: 'b+'c`
RegionPredicate(WhereRegionPredicate),
/// An equality predicate (unsupported)
- EqPredicate(WhereEqPredicate)
+ EqPredicate(WhereEqPredicate),
}
/// A type bound, eg `for<'c> Foo: Send+Clone+'c`
pub ty: P<Ty>,
}
-/// The set of MetaItems that define the compilation environment of the crate,
-/// used to drive conditional compilation
-pub type CrateConfig = Vec<P<MetaItem>> ;
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Crate {
pub module: Mod,
/// Not parsed directly, but created on macro import or `macro_rules!` expansion.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct MacroDef {
- pub ident: Ident,
+ pub name: Name,
pub attrs: Vec<Attribute>,
pub id: NodeId,
pub span: Span,
- pub imported_from: Option<Ident>,
+ pub imported_from: Option<Name>,
pub export: bool,
pub use_locally: bool,
pub allow_internal_unstable: bool,
pub body: Vec<TokenTree>,
}
-pub type MetaItem = Spanned<MetaItem_>;
-
-#[derive(Clone, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum MetaItem_ {
- MetaWord(InternedString),
- MetaList(InternedString, Vec<P<MetaItem>>),
- MetaNameValue(InternedString, Lit),
-}
-
-// can't be derived because the MetaList requires an unordered comparison
-impl PartialEq for MetaItem_ {
- fn eq(&self, other: &MetaItem_) -> bool {
- match *self {
- MetaWord(ref ns) => match *other {
- MetaWord(ref no) => (*ns) == (*no),
- _ => false
- },
- MetaNameValue(ref ns, ref vs) => match *other {
- MetaNameValue(ref no, ref vo) => {
- (*ns) == (*no) && vs.node == vo.node
- }
- _ => false
- },
- MetaList(ref ns, ref miss) => match *other {
- MetaList(ref no, ref miso) => {
- ns == no &&
- miss.iter().all(|mi| miso.iter().any(|x| x.node == mi.node))
- }
- _ => false
- }
- }
- }
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Block {
/// Statements in a block
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct FieldPat {
/// The identifier for the field
- pub ident: Ident,
+ pub name: Name,
/// The pattern the field is destructured to
pub pat: P<Pat>,
pub is_shorthand: bool,
/// which it is. The resolver determines this, and
/// records this pattern's NodeId in an auxiliary
/// set (of "PatIdents that refer to nullary enums")
- PatIdent(BindingMode, SpannedIdent, Option<P<Pat>>),
+ PatIdent(BindingMode, Spanned<Ident>, Option<P<Pat>>),
/// "None" means a * pattern where we don't bind the fields to names.
PatEnum(Path, Option<Vec<P<Pat>>>),
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum UnOp {
- /// The `box` operator
- UnUniq,
/// The `*` operator for dereferencing
UnDeref,
/// The `!` operator for logical inversion
UnNot,
/// The `-` operator for negation
- UnNeg
+ UnNeg,
}
/// A statement
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Sadness.
let spanned = codemap::dummy_spanned(self.clone());
- write!(f, "stmt({}: {})",
+ write!(f,
+ "stmt({}: {})",
util::stmt_id(&spanned),
pprust::stmt_to_string(&spanned))
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Field {
- pub ident: SpannedIdent,
+ pub name: Spanned<Name>,
pub expr: P<Expr>,
pub span: Span,
}
-pub type SpannedIdent = Spanned<Ident>;
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum BlockCheckMode {
DefaultBlock,
UnsafeBlock(UnsafeSource),
PushUnsafeBlock(UnsafeSource),
PopUnsafeBlock(UnsafeSource),
+ // Within this block (but outside a PopUnstableBlock), we suspend checking of stability.
+ PushUnstableBlock,
+ PopUnstableBlock,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
}
/// An expression
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash,)]
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
pub struct Expr {
pub id: NodeId,
pub node: Expr_,
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Expr_ {
- /// First expr is the place; second expr is the value.
- ExprBox(Option<P<Expr>>, P<Expr>),
+ /// A `box x` expression.
+ ExprBox(P<Expr>),
/// An array (`[a, b, c, d]`)
ExprVec(Vec<P<Expr>>),
/// A function call
ExprCall(P<Expr>, Vec<P<Expr>>),
/// A method call (`x.foo::<Bar, Baz>(a, b, c, d)`)
///
- /// The `SpannedIdent` is the identifier for the method name.
+ /// The `Spanned<Name>` is the identifier for the method name.
/// The vector of `Ty`s are the ascripted type parameters for the method
/// (within the angle brackets).
///
///
/// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
/// `ExprMethodCall(foo, [Bar, Baz], [x, a, b, c, d])`.
- ExprMethodCall(SpannedIdent, Vec<P<Ty>>, Vec<P<Expr>>),
+ ExprMethodCall(Spanned<Name>, Vec<P<Ty>>, Vec<P<Expr>>),
/// A tuple (`(a, b, c ,d)`)
ExprTup(Vec<P<Expr>>),
/// A binary operation (For example: `a + b`, `a * b`)
///
/// `if expr { block } else { expr }`
ExprIf(P<Expr>, P<Block>, Option<P<Expr>>),
- // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
/// A while loop, with an optional label
///
/// `'label: while expr { block }`
/// Conditionless loop (can be exited with break, continue, or return)
///
/// `'label: loop { block }`
- // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprLoop(P<Block>, Option<Ident>),
/// A `match` block, with a source that indicates whether or not it is
/// the result of a desugaring, and if so, which kind.
/// For example, `a += 1`.
ExprAssignOp(BinOp, P<Expr>, P<Expr>),
/// Access of a named struct field (`obj.foo`)
- ExprField(P<Expr>, SpannedIdent),
+ ExprField(P<Expr>, Spanned<Name>),
/// Access of an unnamed field of a struct or tuple-struct
///
/// For example, `foo.0`.
/// A referencing operation (`&a` or `&mut a`)
ExprAddrOf(Mutability, P<Expr>),
/// A `break`, with an optional label to break
- ExprBreak(Option<SpannedIdent>),
+ ExprBreak(Option<Spanned<Ident>>),
/// A `continue`, with an optional label
- ExprAgain(Option<SpannedIdent>),
+ ExprAgain(Option<Spanned<Ident>>),
/// A `return`, with an optional value to be returned
ExprRet(Option<P<Expr>>),
/// For example, `[1u8; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
ExprRepeat(P<Expr>, P<Expr>),
-
- /// No-op: used solely so we can pretty-print faithfully
- ExprParen(P<Expr>)
}
/// The explicit Self type in a "qualified path". The actual
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct QSelf {
pub ty: P<Ty>,
- pub position: usize
+ pub position: usize,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum MatchSource {
Normal,
- IfLetDesugar { contains_else_clause: bool },
+ IfLetDesugar {
+ contains_else_clause: bool,
+ },
WhileLetDesugar,
ForLoopDesugar,
}
CaptureByRef,
}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum StrStyle {
- /// A regular string, like `"foo"`
- CookedStr,
- /// A raw string, like `r##"foo"##`
- ///
- /// The uint is the number of `#` symbols used
- RawStr(usize)
-}
-
-/// A literal
-pub type Lit = Spanned<Lit_>;
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum Sign {
- Minus,
- Plus
-}
-
-impl Sign {
- pub fn new<T: IntSign>(n: T) -> Sign {
- n.sign()
- }
-}
-
-pub trait IntSign {
- fn sign(&self) -> Sign;
-}
-macro_rules! doit {
- ($($t:ident)*) => ($(impl IntSign for $t {
- #[allow(unused_comparisons)]
- fn sign(&self) -> Sign {
- if *self < 0 {Minus} else {Plus}
- }
- })*)
-}
-doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum LitIntType {
- SignedIntLit(IntTy, Sign),
- UnsignedIntLit(UintTy),
- UnsuffixedIntLit(Sign)
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum Lit_ {
- /// A string literal (`"foo"`)
- LitStr(InternedString, StrStyle),
- /// A byte string (`b"foo"`)
- LitByteStr(Rc<Vec<u8>>),
- /// A byte char (`b'f'`)
- LitByte(u8),
- /// A character literal (`'a'`)
- LitChar(char),
- /// An integer literal (`1u8`)
- LitInt(u64, LitIntType),
- /// A float literal (`1f64` or `1E10f64`)
- LitFloat(InternedString, FloatTy),
- /// A float literal without a suffix (`1.0 or 1.0E10`)
- LitFloatUnsuffixed(InternedString),
- /// A boolean literal
- LitBool(bool),
-}
-
// NB: If you change this, you'll probably want to change the corresponding
// type structure in middle/ty.rs as well.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub mutbl: Mutability,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct TypeField {
- pub ident: Ident,
- pub mt: MutTy,
- pub span: Span,
-}
-
/// Represents a method's signature in a trait declaration,
/// or in an implementation.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TraitItem {
pub id: NodeId,
- pub ident: Ident,
+ pub name: Name,
pub attrs: Vec<Attribute>,
pub node: TraitItem_,
pub span: Span,
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ImplItem {
pub id: NodeId,
- pub ident: Ident,
+ pub name: Name,
pub vis: Visibility,
pub attrs: Vec<Attribute>,
pub node: ImplItem_,
TypeImplItem(P<Ty>),
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
-pub enum IntTy {
- TyIs,
- TyI8,
- TyI16,
- TyI32,
- TyI64,
-}
-
-impl fmt::Debug for IntTy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
-impl fmt::Display for IntTy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", util::int_ty_to_string(*self, None))
- }
-}
-
-impl IntTy {
- pub fn bit_width(&self) -> Option<usize> {
- Some(match *self {
- TyIs => return None,
- TyI8 => 8,
- TyI16 => 16,
- TyI32 => 32,
- TyI64 => 64,
- })
- }
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
-pub enum UintTy {
- TyUs,
- TyU8,
- TyU16,
- TyU32,
- TyU64,
-}
-
-impl UintTy {
- pub fn bit_width(&self) -> Option<usize> {
- Some(match *self {
- TyUs => return None,
- TyU8 => 8,
- TyU16 => 16,
- TyU32 => 32,
- TyU64 => 64,
- })
- }
-}
-
-impl fmt::Debug for UintTy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
-impl fmt::Display for UintTy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", util::uint_ty_to_string(*self, None))
- }
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
-pub enum FloatTy {
- TyF32,
- TyF64,
-}
-
-impl fmt::Debug for FloatTy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(self, f)
- }
-}
-
-impl fmt::Display for FloatTy {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", util::float_ty_to_string(*self))
- }
-}
-
-impl FloatTy {
- pub fn bit_width(&self) -> usize {
- match *self {
- TyF32 => 32,
- TyF64 => 64,
- }
- }
-}
-
// Bind a type to an associated type: `A=Foo`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct TypeBinding {
pub id: NodeId,
- pub ident: Ident,
+ pub name: Name,
pub ty: P<Ty>,
pub span: Span,
}
TyFloat(FloatTy),
TyStr,
TyBool,
- TyChar
+ TyChar,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub unsafety: Unsafety,
pub abi: Abi,
pub lifetimes: Vec<LifetimeDef>,
- pub decl: P<FnDecl>
+ pub decl: P<FnDecl>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
/// A bare function (e.g. `fn(usize) -> bool`)
TyBareFn(P<BareFnTy>),
/// A tuple (`(A, B, C, D,...)`)
- TyTup(Vec<P<Ty>> ),
+ TyTup(Vec<P<Ty>>),
/// A path (`module::module::...::Type`), optionally
/// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
///
TyInfer,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum AsmDialect {
- AsmAtt,
- AsmIntel
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct InlineAsm {
pub asm: InternedString,
impl Arg {
pub fn new_self(span: Span, mutability: Mutability, self_ident: Ident) -> Arg {
- let path = Spanned{span:span,node:self_ident};
+ let path = Spanned {
+ span: span,
+ node: self_ident,
+ };
Arg {
// HACK(eddyb) fake type for the self argument.
ty: P(Ty {
pat: P(Pat {
id: DUMMY_NODE_ID,
node: PatIdent(BindByValue(mutability), path, None),
- span: span
+ span: span,
}),
- id: DUMMY_NODE_ID
+ id: DUMMY_NODE_ID,
}
}
}
pub struct FnDecl {
pub inputs: Vec<Arg>,
pub output: FunctionRetTy,
- pub variadic: bool
+ pub variadic: bool,
}
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
impl fmt::Display for Unsafety {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(match *self {
- Unsafety::Normal => "normal",
- Unsafety::Unsafe => "unsafe",
- }, f)
+ Unsafety::Normal => "normal",
+ Unsafety::Unsafe => "unsafe",
+ },
+ f)
}
}
match *self {
NoReturn(span) => span,
DefaultReturn(span) => span,
- Return(ref ty) => ty.span
+ Return(ref ty) => ty.span,
}
}
}
/// No self
SelfStatic,
/// `self`
- SelfValue(Ident),
+ SelfValue(Name),
/// `&'lt self`, `&'lt mut self`
- SelfRegion(Option<Lifetime>, Mutability, Ident),
+ SelfRegion(Option<Lifetime>, Mutability, Name),
/// `self: TYPE`
- SelfExplicit(P<Ty>, Ident),
+ SelfExplicit(P<Ty>, Name),
}
pub type ExplicitSelf = Spanned<ExplicitSelf_>;
pub items: Vec<P<ForeignItem>>,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct VariantArg {
- pub ty: P<Ty>,
- pub id: NodeId,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum VariantKind {
- /// Tuple variant, e.g. `Foo(A, B)`
- TupleVariantKind(Vec<VariantArg>),
- /// Struct variant, e.g. `Foo {x: A, y: B}`
- StructVariantKind(P<StructDef>),
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct EnumDef {
pub variants: Vec<P<Variant>>,
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Variant_ {
- pub name: Ident,
+ pub name: Name,
pub attrs: Vec<Attribute>,
- pub kind: VariantKind,
- pub id: NodeId,
+ pub data: VariantData,
/// Explicit discriminant, eg `Foo = 1`
pub disr_expr: Option<P<Expr>>,
- pub vis: Visibility,
}
pub type Variant = Spanned<Variant_>;
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum PathListItem_ {
PathListIdent {
- name: Ident,
+ name: Name,
/// renamed in list, eg `use foo::{bar as baz};`
- rename: Option<Ident>,
- id: NodeId
+ rename: Option<Name>,
+ id: NodeId,
},
PathListMod {
/// renamed in list, eg `use foo::{self as baz};`
- rename: Option<Ident>,
- id: NodeId
- }
+ rename: Option<Name>,
+ id: NodeId,
+ },
}
impl PathListItem_ {
pub fn id(&self) -> NodeId {
match *self {
- PathListIdent { id, .. } | PathListMod { id, .. } => id
+ PathListIdent { id, .. } | PathListMod { id, .. } => id,
+ }
+ }
+
+ pub fn name(&self) -> Option<Name> {
+ match *self {
+ PathListIdent { name, .. } => Some(name),
+ PathListMod { .. } => None,
}
}
- pub fn rename(&self) -> Option<Ident> {
+ pub fn rename(&self) -> Option<Name> {
match *self {
- PathListIdent { rename, .. } | PathListMod { rename, .. } => rename
+ PathListIdent { rename, .. } | PathListMod { rename, .. } => rename,
}
}
}
/// or just
///
/// `foo::bar::baz` (with `as baz` implicitly on the right)
- ViewPathSimple(Ident, Path),
+ ViewPathSimple(Name, Path),
/// `foo::bar::*`
ViewPathGlob(Path),
/// `foo::bar::{a,b,c}`
- ViewPathList(Path, Vec<PathListItem>)
-}
-
-/// Meta-data associated with an item
-pub type Attribute = Spanned<Attribute_>;
-
-/// Distinguishes between Attributes that decorate items and Attributes that
-/// are contained as statements within items. These two cases need to be
-/// distinguished for pretty-printing.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum AttrStyle {
- AttrOuter,
- AttrInner,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub struct AttrId(pub usize);
-
-/// Doc-comments are promoted to attributes that have is_sugared_doc = true
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct Attribute_ {
- pub id: AttrId,
- pub style: AttrStyle,
- pub value: P<MetaItem>,
- pub is_sugared_doc: bool,
+ ViewPathList(Path, Vec<PathListItem>),
}
/// TraitRef's appear in impls.
pub fn inherit_from(&self, parent_visibility: Visibility) -> Visibility {
match self {
&Inherited => parent_visibility,
- &Public => *self
+ &Public => *self,
}
}
}
}
impl StructField_ {
- pub fn ident(&self) -> Option<Ident> {
+ pub fn name(&self) -> Option<Name> {
match self.kind {
- NamedField(ref ident, _) => Some(ident.clone()),
- UnnamedField(_) => None
+ NamedField(name, _) => Some(name),
+ UnnamedField(_) => None,
}
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum StructFieldKind {
- NamedField(Ident, Visibility),
+ NamedField(Name, Visibility),
/// Element of a tuple-like struct
UnnamedField(Visibility),
}
}
}
+/// Fields and Ids of enum variants and structs
+///
+/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all
+/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants).
+/// One shared Id can be successfully used for these two purposes.
+/// Id of the whole enum lives in `Item`.
+///
+/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
+/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of
+/// the variant itself" from enum variants.
+/// Id of the whole struct lives in `Item`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct StructDef {
- /// Fields, not including ctor
- pub fields: Vec<StructField>,
- /// ID of the constructor. This is only used for tuple- or enum-like
- /// structs.
- pub ctor_id: Option<NodeId>,
+pub enum VariantData {
+ Struct(Vec<StructField>, NodeId),
+ Tuple(Vec<StructField>, NodeId),
+ Unit(NodeId),
+}
+
+impl VariantData {
+ pub fn fields(&self) -> &[StructField] {
+ match *self {
+ VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields,
+ _ => &[],
+ }
+ }
+ pub fn id(&self) -> NodeId {
+ match *self {
+ VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id
+ }
+ }
+ pub fn is_struct(&self) -> bool {
+ if let VariantData::Struct(..) = *self { true } else { false }
+ }
+ pub fn is_tuple(&self) -> bool {
+ if let VariantData::Tuple(..) = *self { true } else { false }
+ }
+ pub fn is_unit(&self) -> bool {
+ if let VariantData::Unit(..) = *self { true } else { false }
+ }
}
/*
/// The name might be a dummy name in case of anonymous items
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Item {
- pub ident: Ident,
+ pub name: Name,
pub attrs: Vec<Attribute>,
pub id: NodeId,
pub node: Item_,
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
ItemEnum(EnumDef, Generics),
/// A struct definition, e.g. `struct Foo<A> {x: A}`
- ItemStruct(P<StructDef>, Generics),
+ ItemStruct(VariantData, Generics),
/// Represents a Trait Declaration
- ItemTrait(Unsafety,
- Generics,
- TyParamBounds,
- Vec<P<TraitItem>>),
+ ItemTrait(Unsafety, Generics, TyParamBounds, Vec<P<TraitItem>>),
// Default trait implementations
///
ItemStruct(..) => "struct",
ItemTrait(..) => "trait",
ItemImpl(..) |
- ItemDefaultImpl(..) => "item"
+ ItemDefaultImpl(..) => "item",
}
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct ForeignItem {
- pub ident: Ident,
+ pub name: Name,
pub attrs: Vec<Attribute>,
pub node: ForeignItem_,
pub id: NodeId,
pub fn descriptive_variant(&self) -> &str {
match *self {
ForeignItemFn(..) => "foreign function",
- ForeignItemStatic(..) => "foreign static item"
+ ForeignItemStatic(..) => "foreign static item",
}
}
}
#![feature(staged_api)]
#![feature(str_char)]
#![feature(filling_drop)]
-#![feature(str_escape)]
-#![cfg_attr(test, feature(test))]
extern crate serialize;
-#[macro_use] extern crate log;
-#[macro_use] extern crate syntax;
-#[macro_use] #[no_link] extern crate rustc_bitflags;
+#[macro_use]
+extern crate log;
+#[macro_use]
+extern crate syntax;
+#[macro_use]
+#[no_link]
+extern crate rustc_bitflags;
extern crate serialize as rustc_serialize; // used by deriving
pub mod lowering;
pub mod fold;
pub mod visit;
-pub mod attr;
pub mod util;
pub mod print {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Lowers the AST to the HIR
+// Lowers the AST to the HIR.
+//
+// Since the AST and HIR are fairly similar, this is mostly a simple procedure,
+// much like a fold. Where lowering involves a bit more work things get more
+// interesting and there are some invariants you should know about. These mostly
+// concern spans and ids.
+//
+// Spans are assigned to AST nodes during parsing and then are modified during
+// expansion to indicate the origin of a node and the process it went through
+// being expanded. Ids are assigned to AST nodes just before lowering.
+//
+// For the simpler lowering steps, ids and spans should be preserved. Unlike
+// expansion we do not preserve the process of lowering in the spans, so spans
+// should not be modified here. When creating a new node (as opposed to
+// 'folding' an existing one), then you create a new id using `next_id()`.
+//
+// You must ensure that ids are unique. That means that you should only use the
+// id from an AST node in a single HIR node (you can assume that AST node ids
+// are unique). Every new node must have a unique id. Avoid cloning HIR nodes.
+// If you do, you must then set the new node's id to a fresh one.
+//
+// Lowering must be reproducable (the compiler only lowers once, but tools and
+// custom lints may lower an AST node to a HIR node to interact with the
+// compiler). The most interesting bit of this is ids - if you lower an AST node
+// and create new HIR nodes with fresh ids, when re-lowering the same node, you
+// must ensure you get the same ids! To do this, we keep track of the next id
+// when we translate a node which requires new ids. By checking this cache and
+// using node ids starting with the cached id, we ensure ids are reproducible.
+// To use this system, you just need to hold on to a CachedIdSetter object
+// whilst lowering. This is an RAII object that takes care of setting and
+// restoring the cached id, etc.
+//
+// This whole system relies on node ids being incremented one at a time and
+// all increments being for lowering. This means that you should not call any
+// non-lowering function which will use new node ids.
+//
+// We must also cache gensym'ed Idents to ensure that we get the same Ident
+// every time we lower a node with gensym'ed names. One consequence of this is
+// that you can only gensym a name once in a lowering (you don't need to worry
+// about nested lowering though). That's because we cache based on the name and
+// the currently cached node id, which is unique per lowered node.
+//
+// Spans are used for error messages and for tools to map semantics back to
+// source code. It is therefore not as important with spans as ids to be strict
+// about use (you can't break the compiler by screwing up a span). Obviously, a
+// HIR node can only have a single span. But multiple nodes can have the same
+// span and spans don't need to be kept in order, etc. Where code is preserved
+// by lowering, it should have the same span as in the AST. Where HIR nodes are
+// new it is probably best to give a span for the whole AST node being lowered.
+// All nodes should have real spans, don't use dummy spans. Tools are likely to
+// get confused if the spans from leaf AST nodes occur in multiple places
+// in the HIR, especially for multiple identifiers.
use hir;
+use std::collections::HashMap;
+
use syntax::ast::*;
use syntax::ptr::P;
-use syntax::codemap::Spanned;
+use syntax::codemap::{respan, Spanned, Span};
use syntax::owned_slice::OwnedSlice;
+use syntax::parse::token::{self, str_to_ident};
+use syntax::std_inject;
+
+use std::cell::{Cell, RefCell};
+
+pub struct LoweringContext<'a> {
+ crate_root: Option<&'static str>,
+ // Map AST ids to ids used for expanded nodes.
+ id_cache: RefCell<HashMap<NodeId, NodeId>>,
+ // Use if there are no cached ids for the current node.
+ id_assigner: &'a NodeIdAssigner,
+ // 0 == no cached id. Must be incremented to align with previous id
+ // incrementing.
+ cached_id: Cell<u32>,
+ // Keep track of gensym'ed idents.
+ gensym_cache: RefCell<HashMap<(NodeId, &'static str), Ident>>,
+ // A copy of cached_id, but is also set to an id while it is being cached.
+ gensym_key: Cell<u32>,
+}
+
+impl<'a, 'hir> LoweringContext<'a> {
+ pub fn new(id_assigner: &'a NodeIdAssigner, c: Option<&Crate>) -> LoweringContext<'a> {
+ let crate_root = c.and_then(|c| {
+ if std_inject::no_core(c) {
+ None
+ } else if std_inject::no_std(c) {
+ Some("core")
+ } else {
+ Some("std")
+ }
+ });
+
+ LoweringContext {
+ crate_root: crate_root,
+ id_cache: RefCell::new(HashMap::new()),
+ id_assigner: id_assigner,
+ cached_id: Cell::new(0),
+ gensym_cache: RefCell::new(HashMap::new()),
+ gensym_key: Cell::new(0),
+ }
+ }
+ fn next_id(&self) -> NodeId {
+ let cached = self.cached_id.get();
+ if cached == 0 {
+ return self.id_assigner.next_node_id()
+ }
-pub fn lower_meta_items(meta_items: &Vec<P<MetaItem>>) -> Vec<P<hir::MetaItem>> {
- meta_items.iter().map(|x| lower_meta_item(x)).collect()
+ self.cached_id.set(cached + 1);
+ cached
+ }
+
+ fn str_to_ident(&self, s: &'static str) -> Ident {
+ let cached_id = self.gensym_key.get();
+ if cached_id == 0 {
+ return token::gensym_ident(s);
+ }
+
+ let cached = self.gensym_cache.borrow().contains_key(&(cached_id, s));
+ if cached {
+ self.gensym_cache.borrow()[&(cached_id, s)]
+ } else {
+ let result = token::gensym_ident(s);
+ self.gensym_cache.borrow_mut().insert((cached_id, s), result);
+ result
+ }
+ }
}
-pub fn lower_view_path(view_path: &ViewPath) -> P<hir::ViewPath> {
+pub fn lower_view_path(_lctx: &LoweringContext, view_path: &ViewPath) -> P<hir::ViewPath> {
P(Spanned {
node: match view_path.node {
ViewPathSimple(ident, ref path) => {
- hir::ViewPathSimple(ident, lower_path(path))
+ hir::ViewPathSimple(ident.name, lower_path(_lctx, path))
}
ViewPathGlob(ref path) => {
- hir::ViewPathGlob(lower_path(path))
+ hir::ViewPathGlob(lower_path(_lctx, path))
}
ViewPathList(ref path, ref path_list_idents) => {
- hir::ViewPathList(lower_path(path),
- path_list_idents.iter().map(|path_list_ident| {
- Spanned {
- node: match path_list_ident.node {
- PathListIdent { id, name, rename } =>
- hir::PathListIdent {
- id: id,
- name: name,
- rename: rename.clone(),
- },
- PathListMod { id, rename } =>
- hir::PathListMod { id: id, rename: rename.clone() }
- },
- span: path_list_ident.span
- }
- }).collect())
+ hir::ViewPathList(lower_path(_lctx, path),
+ path_list_idents.iter()
+ .map(|path_list_ident| {
+ Spanned {
+ node: match path_list_ident.node {
+ PathListIdent { id, name, rename } =>
+ hir::PathListIdent {
+ id: id,
+ name: name.name,
+ rename: rename.map(|x| x.name),
+ },
+ PathListMod { id, rename } =>
+ hir::PathListMod {
+ id: id,
+ rename: rename.map(|x| x.name),
+ },
+ },
+ span: path_list_ident.span,
+ }
+ })
+ .collect())
}
},
span: view_path.span,
})
}
-pub fn lower_attrs(attrs: &Vec<Attribute>) -> Vec<hir::Attribute> {
- attrs.iter().map(|x| lower_attribute(x)).collect()
-}
-
-pub fn lower_arm(arm: &Arm) -> hir::Arm {
+pub fn lower_arm(_lctx: &LoweringContext, arm: &Arm) -> hir::Arm {
hir::Arm {
- attrs: lower_attrs(&arm.attrs),
- pats: arm.pats.iter().map(|x| lower_pat(x)).collect(),
- guard: arm.guard.as_ref().map(|ref x| lower_expr(x)),
- body: lower_expr(&arm.body),
+ attrs: arm.attrs.clone(),
+ pats: arm.pats.iter().map(|x| lower_pat(_lctx, x)).collect(),
+ guard: arm.guard.as_ref().map(|ref x| lower_expr(_lctx, x)),
+ body: lower_expr(_lctx, &arm.body),
}
}
-pub fn lower_decl(d: &Decl) -> P<hir::Decl> {
+pub fn lower_decl(_lctx: &LoweringContext, d: &Decl) -> P<hir::Decl> {
match d.node {
DeclLocal(ref l) => P(Spanned {
- node: hir::DeclLocal(lower_local(l)),
- span: d.span
+ node: hir::DeclLocal(lower_local(_lctx, l)),
+ span: d.span,
}),
DeclItem(ref it) => P(Spanned {
- node: hir::DeclItem(lower_item(it)),
- span: d.span
+ node: hir::DeclItem(lower_item(_lctx, it)),
+ span: d.span,
}),
}
}
-pub fn lower_ty_binding(b: &TypeBinding) -> P<hir::TypeBinding> {
- P(hir::TypeBinding { id: b.id, ident: b.ident, ty: lower_ty(&b.ty), span: b.span })
+pub fn lower_ty_binding(_lctx: &LoweringContext, b: &TypeBinding) -> P<hir::TypeBinding> {
+ P(hir::TypeBinding {
+ id: b.id,
+ name: b.ident.name,
+ ty: lower_ty(_lctx, &b.ty),
+ span: b.span,
+ })
}
-pub fn lower_ty(t: &Ty) -> P<hir::Ty> {
+pub fn lower_ty(_lctx: &LoweringContext, t: &Ty) -> P<hir::Ty> {
P(hir::Ty {
id: t.id,
node: match t.node {
TyInfer => hir::TyInfer,
- TyVec(ref ty) => hir::TyVec(lower_ty(ty)),
- TyPtr(ref mt) => hir::TyPtr(lower_mt(mt)),
+ TyVec(ref ty) => hir::TyVec(lower_ty(_lctx, ty)),
+ TyPtr(ref mt) => hir::TyPtr(lower_mt(_lctx, mt)),
TyRptr(ref region, ref mt) => {
- hir::TyRptr(lower_opt_lifetime(region), lower_mt(mt))
+ hir::TyRptr(lower_opt_lifetime(_lctx, region),
+ lower_mt(_lctx, mt))
}
TyBareFn(ref f) => {
hir::TyBareFn(P(hir::BareFnTy {
- lifetimes: lower_lifetime_defs(&f.lifetimes),
- unsafety: lower_unsafety(f.unsafety),
+ lifetimes: lower_lifetime_defs(_lctx, &f.lifetimes),
+ unsafety: lower_unsafety(_lctx, f.unsafety),
abi: f.abi,
- decl: lower_fn_decl(&f.decl)
+ decl: lower_fn_decl(_lctx, &f.decl),
}))
}
- TyTup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(ty)).collect()),
- TyParen(ref ty) => hir::TyParen(lower_ty(ty)),
+ TyTup(ref tys) => hir::TyTup(tys.iter().map(|ty| lower_ty(_lctx, ty)).collect()),
+ TyParen(ref ty) => hir::TyParen(lower_ty(_lctx, ty)),
TyPath(ref qself, ref path) => {
let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
hir::QSelf {
- ty: lower_ty(ty),
- position: position
+ ty: lower_ty(_lctx, ty),
+ position: position,
}
});
- hir::TyPath(qself, lower_path(path))
+ hir::TyPath(qself, lower_path(_lctx, path))
}
TyObjectSum(ref ty, ref bounds) => {
- hir::TyObjectSum(lower_ty(ty),
- lower_bounds(bounds))
+ hir::TyObjectSum(lower_ty(_lctx, ty), lower_bounds(_lctx, bounds))
}
TyFixedLengthVec(ref ty, ref e) => {
- hir::TyFixedLengthVec(lower_ty(ty), lower_expr(e))
+ hir::TyFixedLengthVec(lower_ty(_lctx, ty), lower_expr(_lctx, e))
}
TyTypeof(ref expr) => {
- hir::TyTypeof(lower_expr(expr))
+ hir::TyTypeof(lower_expr(_lctx, expr))
}
TyPolyTraitRef(ref bounds) => {
- hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(b)).collect())
+ hir::TyPolyTraitRef(bounds.iter().map(|b| lower_ty_param_bound(_lctx, b)).collect())
}
TyMac(_) => panic!("TyMac should have been expanded by now."),
},
})
}
-pub fn lower_foreign_mod(fm: &ForeignMod) -> hir::ForeignMod {
+pub fn lower_foreign_mod(_lctx: &LoweringContext, fm: &ForeignMod) -> hir::ForeignMod {
hir::ForeignMod {
abi: fm.abi,
- items: fm.items.iter().map(|x| lower_foreign_item(x)).collect(),
+ items: fm.items.iter().map(|x| lower_foreign_item(_lctx, x)).collect(),
}
}
-pub fn lower_variant(v: &Variant) -> P<hir::Variant> {
+pub fn lower_variant(_lctx: &LoweringContext, v: &Variant) -> P<hir::Variant> {
P(Spanned {
node: hir::Variant_ {
- id: v.node.id,
- name: v.node.name,
- attrs: lower_attrs(&v.node.attrs),
- kind: match v.node.kind {
- TupleVariantKind(ref variant_args) => {
- hir::TupleVariantKind(variant_args.iter().map(|ref x|
- lower_variant_arg(x)).collect())
- }
- StructVariantKind(ref struct_def) => {
- hir::StructVariantKind(lower_struct_def(struct_def))
- }
- },
- disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(e)),
- vis: lower_visibility(v.node.vis),
+ name: v.node.name.name,
+ attrs: v.node.attrs.clone(),
+ data: lower_variant_data(_lctx, &v.node.data),
+ disr_expr: v.node.disr_expr.as_ref().map(|e| lower_expr(_lctx, e)),
},
span: v.span,
})
}
-pub fn lower_path(p: &Path) -> hir::Path {
+pub fn lower_path(_lctx: &LoweringContext, p: &Path) -> hir::Path {
hir::Path {
global: p.global,
- segments: p.segments.iter().map(|&PathSegment {identifier, ref parameters}|
- hir::PathSegment {
- identifier: identifier,
- parameters: lower_path_parameters(parameters),
- }).collect(),
+ segments: p.segments
+ .iter()
+ .map(|&PathSegment { identifier, ref parameters }| {
+ hir::PathSegment {
+ identifier: identifier,
+ parameters: lower_path_parameters(_lctx, parameters),
+ }
+ })
+ .collect(),
span: p.span,
}
}
-pub fn lower_path_parameters(path_parameters: &PathParameters) -> hir::PathParameters {
+pub fn lower_path_parameters(_lctx: &LoweringContext,
+ path_parameters: &PathParameters)
+ -> hir::PathParameters {
match *path_parameters {
AngleBracketedParameters(ref data) =>
- hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(data)),
+ hir::AngleBracketedParameters(lower_angle_bracketed_parameter_data(_lctx, data)),
ParenthesizedParameters(ref data) =>
- hir::ParenthesizedParameters(lower_parenthesized_parameter_data(data)),
+ hir::ParenthesizedParameters(lower_parenthesized_parameter_data(_lctx, data)),
}
}
-pub fn lower_angle_bracketed_parameter_data(data: &AngleBracketedParameterData)
+pub fn lower_angle_bracketed_parameter_data(_lctx: &LoweringContext,
+ data: &AngleBracketedParameterData)
-> hir::AngleBracketedParameterData {
let &AngleBracketedParameterData { ref lifetimes, ref types, ref bindings } = data;
hir::AngleBracketedParameterData {
- lifetimes: lower_lifetimes(lifetimes),
- types: types.iter().map(|ty| lower_ty(ty)).collect(),
- bindings: bindings.iter().map(|b| lower_ty_binding(b)).collect(),
+ lifetimes: lower_lifetimes(_lctx, lifetimes),
+ types: types.iter().map(|ty| lower_ty(_lctx, ty)).collect(),
+ bindings: bindings.iter().map(|b| lower_ty_binding(_lctx, b)).collect(),
}
}
-pub fn lower_parenthesized_parameter_data(data: &ParenthesizedParameterData)
+pub fn lower_parenthesized_parameter_data(_lctx: &LoweringContext,
+ data: &ParenthesizedParameterData)
-> hir::ParenthesizedParameterData {
let &ParenthesizedParameterData { ref inputs, ref output, span } = data;
hir::ParenthesizedParameterData {
- inputs: inputs.iter().map(|ty| lower_ty(ty)).collect(),
- output: output.as_ref().map(|ty| lower_ty(ty)),
+ inputs: inputs.iter().map(|ty| lower_ty(_lctx, ty)).collect(),
+ output: output.as_ref().map(|ty| lower_ty(_lctx, ty)),
span: span,
}
}
-pub fn lower_local(l: &Local) -> P<hir::Local> {
+pub fn lower_local(_lctx: &LoweringContext, l: &Local) -> P<hir::Local> {
P(hir::Local {
- id: l.id,
- ty: l.ty.as_ref().map(|t| lower_ty(t)),
- pat: lower_pat(&l.pat),
- init: l.init.as_ref().map(|e| lower_expr(e)),
- span: l.span,
- })
-}
-
-pub fn lower_attribute(at: &Attribute) -> hir::Attribute {
- Spanned {
- node: hir::Attribute_ {
- id: hir::AttrId(at.node.id.0),
- style: lower_attr_style(at.node.style),
- value: lower_meta_item(&at.node.value),
- is_sugared_doc: at.node.is_sugared_doc,
- },
- span: at.span,
- }
-}
-
-// FIXME we should probably just unify hir and ast Attributes.
-pub fn unlower_attribute(at: &hir::Attribute) -> Attribute {
- Spanned {
- node: Attribute_ {
- id: AttrId(at.node.id.0),
- style: unlower_attr_style(at.node.style),
- value: unlower_meta_item(&at.node.value),
- is_sugared_doc: at.node.is_sugared_doc,
- },
- span: at.span,
- }
+ id: l.id,
+ ty: l.ty.as_ref().map(|t| lower_ty(_lctx, t)),
+ pat: lower_pat(_lctx, &l.pat),
+ init: l.init.as_ref().map(|e| lower_expr(_lctx, e)),
+ span: l.span,
+ })
}
-pub fn lower_explicit_self_underscore(es: &ExplicitSelf_) -> hir::ExplicitSelf_ {
+pub fn lower_explicit_self_underscore(_lctx: &LoweringContext,
+ es: &ExplicitSelf_)
+ -> hir::ExplicitSelf_ {
match *es {
SelfStatic => hir::SelfStatic,
- SelfValue(v) => hir::SelfValue(v),
+ SelfValue(v) => hir::SelfValue(v.name),
SelfRegion(ref lifetime, m, ident) => {
- hir::SelfRegion(lower_opt_lifetime(lifetime), lower_mutability(m), ident)
+ hir::SelfRegion(lower_opt_lifetime(_lctx, lifetime),
+ lower_mutability(_lctx, m),
+ ident.name)
}
SelfExplicit(ref typ, ident) => {
- hir::SelfExplicit(lower_ty(typ), ident)
+ hir::SelfExplicit(lower_ty(_lctx, typ), ident.name)
}
}
}
-pub fn lower_mutability(m: Mutability) -> hir::Mutability {
+pub fn lower_mutability(_lctx: &LoweringContext, m: Mutability) -> hir::Mutability {
match m {
MutMutable => hir::MutMutable,
MutImmutable => hir::MutImmutable,
}
}
-pub fn lower_explicit_self(s: &ExplicitSelf) -> hir::ExplicitSelf {
- Spanned { node: lower_explicit_self_underscore(&s.node), span: s.span }
-}
-
-
-pub fn lower_meta_item(mi: &MetaItem) -> P<hir::MetaItem> {
- P(Spanned {
- node: match mi.node {
- MetaWord(ref id) => hir::MetaWord(id.clone()),
- MetaList(ref id, ref mis) => {
- hir::MetaList(id.clone(), mis.iter().map(|mi| lower_meta_item(mi)).collect())
- }
- MetaNameValue(ref id, ref s) => hir::MetaNameValue(id.clone(), lower_lit(s))
- },
- span: mi.span,
- })
-}
-
-pub fn unlower_meta_item(mi: &hir::MetaItem) -> P<MetaItem> {
- P(Spanned {
- node: match mi.node {
- hir::MetaWord(ref id) => MetaWord(id.clone()),
- hir::MetaList(ref id, ref mis) => {
- MetaList(id.clone(), mis.iter().map(|mi| unlower_meta_item(mi)).collect())
- }
- hir::MetaNameValue(ref id, ref s) => MetaNameValue(id.clone(), unlower_lit(s))
- },
- span: mi.span,
- })
+pub fn lower_explicit_self(_lctx: &LoweringContext, s: &ExplicitSelf) -> hir::ExplicitSelf {
+ Spanned {
+ node: lower_explicit_self_underscore(_lctx, &s.node),
+ span: s.span,
+ }
}
-pub fn lower_arg(arg: &Arg) -> hir::Arg {
- hir::Arg { id: arg.id, pat: lower_pat(&arg.pat), ty: lower_ty(&arg.ty) }
+pub fn lower_arg(_lctx: &LoweringContext, arg: &Arg) -> hir::Arg {
+ hir::Arg {
+ id: arg.id,
+ pat: lower_pat(_lctx, &arg.pat),
+ ty: lower_ty(_lctx, &arg.ty),
+ }
}
-pub fn lower_fn_decl(decl: &FnDecl) -> P<hir::FnDecl> {
+pub fn lower_fn_decl(_lctx: &LoweringContext, decl: &FnDecl) -> P<hir::FnDecl> {
P(hir::FnDecl {
- inputs: decl.inputs.iter().map(|x| lower_arg(x)).collect(),
+ inputs: decl.inputs.iter().map(|x| lower_arg(_lctx, x)).collect(),
output: match decl.output {
- Return(ref ty) => hir::Return(lower_ty(ty)),
+ Return(ref ty) => hir::Return(lower_ty(_lctx, ty)),
DefaultReturn(span) => hir::DefaultReturn(span),
- NoReturn(span) => hir::NoReturn(span)
+ NoReturn(span) => hir::NoReturn(span),
},
variadic: decl.variadic,
})
}
-pub fn lower_ty_param_bound(tpb: &TyParamBound) -> hir::TyParamBound {
+pub fn lower_ty_param_bound(_lctx: &LoweringContext, tpb: &TyParamBound) -> hir::TyParamBound {
match *tpb {
TraitTyParamBound(ref ty, modifier) => {
- hir::TraitTyParamBound(lower_poly_trait_ref(ty), lower_trait_bound_modifier(modifier))
+ hir::TraitTyParamBound(lower_poly_trait_ref(_lctx, ty),
+ lower_trait_bound_modifier(_lctx, modifier))
+ }
+ RegionTyParamBound(ref lifetime) => {
+ hir::RegionTyParamBound(lower_lifetime(_lctx, lifetime))
}
- RegionTyParamBound(ref lifetime) => hir::RegionTyParamBound(lower_lifetime(lifetime)),
}
}
-pub fn lower_ty_param(tp: &TyParam) -> hir::TyParam {
+pub fn lower_ty_param(_lctx: &LoweringContext, tp: &TyParam) -> hir::TyParam {
hir::TyParam {
id: tp.id,
- ident: tp.ident,
- bounds: lower_bounds(&tp.bounds),
- default: tp.default.as_ref().map(|x| lower_ty(x)),
+ name: tp.ident.name,
+ bounds: lower_bounds(_lctx, &tp.bounds),
+ default: tp.default.as_ref().map(|x| lower_ty(_lctx, x)),
span: tp.span,
}
}
-pub fn lower_ty_params(tps: &OwnedSlice<TyParam>) -> OwnedSlice<hir::TyParam> {
- tps.iter().map(|tp| lower_ty_param(tp)).collect()
+pub fn lower_ty_params(_lctx: &LoweringContext,
+ tps: &OwnedSlice<TyParam>)
+ -> OwnedSlice<hir::TyParam> {
+ tps.iter().map(|tp| lower_ty_param(_lctx, tp)).collect()
}
-pub fn lower_lifetime(l: &Lifetime) -> hir::Lifetime {
- hir::Lifetime { id: l.id, name: l.name, span: l.span }
+pub fn lower_lifetime(_lctx: &LoweringContext, l: &Lifetime) -> hir::Lifetime {
+ hir::Lifetime {
+ id: l.id,
+ name: l.name,
+ span: l.span,
+ }
}
-pub fn lower_lifetime_def(l: &LifetimeDef) -> hir::LifetimeDef {
- hir::LifetimeDef { lifetime: lower_lifetime(&l.lifetime), bounds: lower_lifetimes(&l.bounds) }
+pub fn lower_lifetime_def(_lctx: &LoweringContext, l: &LifetimeDef) -> hir::LifetimeDef {
+ hir::LifetimeDef {
+ lifetime: lower_lifetime(_lctx, &l.lifetime),
+ bounds: lower_lifetimes(_lctx, &l.bounds),
+ }
}
-pub fn lower_lifetimes(lts: &Vec<Lifetime>) -> Vec<hir::Lifetime> {
- lts.iter().map(|l| lower_lifetime(l)).collect()
+pub fn lower_lifetimes(_lctx: &LoweringContext, lts: &Vec<Lifetime>) -> Vec<hir::Lifetime> {
+ lts.iter().map(|l| lower_lifetime(_lctx, l)).collect()
}
-pub fn lower_lifetime_defs(lts: &Vec<LifetimeDef>) -> Vec<hir::LifetimeDef> {
- lts.iter().map(|l| lower_lifetime_def(l)).collect()
+pub fn lower_lifetime_defs(_lctx: &LoweringContext,
+ lts: &Vec<LifetimeDef>)
+ -> Vec<hir::LifetimeDef> {
+ lts.iter().map(|l| lower_lifetime_def(_lctx, l)).collect()
}
-pub fn lower_opt_lifetime(o_lt: &Option<Lifetime>) -> Option<hir::Lifetime> {
- o_lt.as_ref().map(|lt| lower_lifetime(lt))
+pub fn lower_opt_lifetime(_lctx: &LoweringContext,
+ o_lt: &Option<Lifetime>)
+ -> Option<hir::Lifetime> {
+ o_lt.as_ref().map(|lt| lower_lifetime(_lctx, lt))
}
-pub fn lower_generics(g: &Generics) -> hir::Generics {
+pub fn lower_generics(_lctx: &LoweringContext, g: &Generics) -> hir::Generics {
hir::Generics {
- ty_params: lower_ty_params(&g.ty_params),
- lifetimes: lower_lifetime_defs(&g.lifetimes),
- where_clause: lower_where_clause(&g.where_clause),
+ ty_params: lower_ty_params(_lctx, &g.ty_params),
+ lifetimes: lower_lifetime_defs(_lctx, &g.lifetimes),
+ where_clause: lower_where_clause(_lctx, &g.where_clause),
}
}
-pub fn lower_where_clause(wc: &WhereClause) -> hir::WhereClause {
+pub fn lower_where_clause(_lctx: &LoweringContext, wc: &WhereClause) -> hir::WhereClause {
hir::WhereClause {
id: wc.id,
- predicates: wc.predicates.iter().map(|predicate|
- lower_where_predicate(predicate)).collect(),
+ predicates: wc.predicates
+ .iter()
+ .map(|predicate| lower_where_predicate(_lctx, predicate))
+ .collect(),
}
}
-pub fn lower_where_predicate(pred: &WherePredicate) -> hir::WherePredicate {
+pub fn lower_where_predicate(_lctx: &LoweringContext,
+ pred: &WherePredicate)
+ -> hir::WherePredicate {
match *pred {
WherePredicate::BoundPredicate(WhereBoundPredicate{ ref bound_lifetimes,
ref bounded_ty,
ref bounds,
span}) => {
hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
- bound_lifetimes: lower_lifetime_defs(bound_lifetimes),
- bounded_ty: lower_ty(bounded_ty),
- bounds: bounds.iter().map(|x| lower_ty_param_bound(x)).collect(),
- span: span
+ bound_lifetimes: lower_lifetime_defs(_lctx, bound_lifetimes),
+ bounded_ty: lower_ty(_lctx, bounded_ty),
+ bounds: bounds.iter().map(|x| lower_ty_param_bound(_lctx, x)).collect(),
+ span: span,
})
}
WherePredicate::RegionPredicate(WhereRegionPredicate{ ref lifetime,
span}) => {
hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate {
span: span,
- lifetime: lower_lifetime(lifetime),
- bounds: bounds.iter().map(|bound| lower_lifetime(bound)).collect()
+ lifetime: lower_lifetime(_lctx, lifetime),
+ bounds: bounds.iter().map(|bound| lower_lifetime(_lctx, bound)).collect(),
})
}
WherePredicate::EqPredicate(WhereEqPredicate{ id,
ref path,
ref ty,
span}) => {
- hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{
+ hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
id: id,
- path: lower_path(path),
- ty:lower_ty(ty),
- span: span
+ path: lower_path(_lctx, path),
+ ty: lower_ty(_lctx, ty),
+ span: span,
})
}
}
}
-pub fn lower_struct_def(sd: &StructDef) -> P<hir::StructDef> {
- P(hir::StructDef {
- fields: sd.fields.iter().map(|f| lower_struct_field(f)).collect(),
- ctor_id: sd.ctor_id,
- })
+pub fn lower_variant_data(_lctx: &LoweringContext, vdata: &VariantData) -> hir::VariantData {
+ match *vdata {
+ VariantData::Struct(ref fields, id) => {
+ hir::VariantData::Struct(fields.iter()
+ .map(|f| lower_struct_field(_lctx, f)).collect(), id)
+ }
+ VariantData::Tuple(ref fields, id) => {
+ hir::VariantData::Tuple(fields.iter()
+ .map(|f| lower_struct_field(_lctx, f)).collect(), id)
+ }
+ VariantData::Unit(id) => hir::VariantData::Unit(id)
+ }
}
-pub fn lower_trait_ref(p: &TraitRef) -> hir::TraitRef {
- hir::TraitRef { path: lower_path(&p.path), ref_id: p.ref_id }
+pub fn lower_trait_ref(_lctx: &LoweringContext, p: &TraitRef) -> hir::TraitRef {
+ hir::TraitRef {
+ path: lower_path(_lctx, &p.path),
+ ref_id: p.ref_id,
+ }
}
-pub fn lower_poly_trait_ref(p: &PolyTraitRef) -> hir::PolyTraitRef {
+pub fn lower_poly_trait_ref(_lctx: &LoweringContext, p: &PolyTraitRef) -> hir::PolyTraitRef {
hir::PolyTraitRef {
- bound_lifetimes: lower_lifetime_defs(&p.bound_lifetimes),
- trait_ref: lower_trait_ref(&p.trait_ref),
+ bound_lifetimes: lower_lifetime_defs(_lctx, &p.bound_lifetimes),
+ trait_ref: lower_trait_ref(_lctx, &p.trait_ref),
span: p.span,
}
}
-pub fn lower_struct_field(f: &StructField) -> hir::StructField {
+pub fn lower_struct_field(_lctx: &LoweringContext, f: &StructField) -> hir::StructField {
Spanned {
node: hir::StructField_ {
id: f.node.id,
- kind: lower_struct_field_kind(&f.node.kind),
- ty: lower_ty(&f.node.ty),
- attrs: lower_attrs(&f.node.attrs),
+ kind: lower_struct_field_kind(_lctx, &f.node.kind),
+ ty: lower_ty(_lctx, &f.node.ty),
+ attrs: f.node.attrs.clone(),
},
span: f.span,
}
}
-pub fn lower_field(f: &Field) -> hir::Field {
- hir::Field { ident: f.ident, expr: lower_expr(&f.expr), span: f.span }
+pub fn lower_field(_lctx: &LoweringContext, f: &Field) -> hir::Field {
+ hir::Field {
+ name: respan(f.ident.span, f.ident.node.name),
+ expr: lower_expr(_lctx, &f.expr),
+ span: f.span,
+ }
}
-pub fn lower_mt(mt: &MutTy) -> hir::MutTy {
- hir::MutTy { ty: lower_ty(&mt.ty), mutbl: lower_mutability(mt.mutbl) }
+pub fn lower_mt(_lctx: &LoweringContext, mt: &MutTy) -> hir::MutTy {
+ hir::MutTy {
+ ty: lower_ty(_lctx, &mt.ty),
+ mutbl: lower_mutability(_lctx, mt.mutbl),
+ }
}
-pub fn lower_opt_bounds(b: &Option<OwnedSlice<TyParamBound>>)
+pub fn lower_opt_bounds(_lctx: &LoweringContext,
+ b: &Option<OwnedSlice<TyParamBound>>)
-> Option<OwnedSlice<hir::TyParamBound>> {
- b.as_ref().map(|ref bounds| lower_bounds(bounds))
+ b.as_ref().map(|ref bounds| lower_bounds(_lctx, bounds))
}
-fn lower_bounds(bounds: &TyParamBounds) -> hir::TyParamBounds {
- bounds.iter().map(|bound| lower_ty_param_bound(bound)).collect()
+fn lower_bounds(_lctx: &LoweringContext, bounds: &TyParamBounds) -> hir::TyParamBounds {
+ bounds.iter().map(|bound| lower_ty_param_bound(_lctx, bound)).collect()
}
-fn lower_variant_arg(va: &VariantArg) -> hir::VariantArg {
- hir::VariantArg { id: va.id, ty: lower_ty(&va.ty) }
-}
-
-pub fn lower_block(b: &Block) -> P<hir::Block> {
+pub fn lower_block(_lctx: &LoweringContext, b: &Block) -> P<hir::Block> {
P(hir::Block {
id: b.id,
- stmts: b.stmts.iter().map(|s| lower_stmt(s)).collect(),
- expr: b.expr.as_ref().map(|ref x| lower_expr(x)),
- rules: lower_block_check_mode(&b.rules),
+ stmts: b.stmts.iter().map(|s| lower_stmt(_lctx, s)).collect(),
+ expr: b.expr.as_ref().map(|ref x| lower_expr(_lctx, x)),
+ rules: lower_block_check_mode(_lctx, &b.rules),
span: b.span,
})
}
-pub fn lower_item_underscore(i: &Item_) -> hir::Item_ {
+pub fn lower_item_underscore(_lctx: &LoweringContext, i: &Item_) -> hir::Item_ {
match *i {
ItemExternCrate(string) => hir::ItemExternCrate(string),
ItemUse(ref view_path) => {
- hir::ItemUse(lower_view_path(view_path))
+ hir::ItemUse(lower_view_path(_lctx, view_path))
}
ItemStatic(ref t, m, ref e) => {
- hir::ItemStatic(lower_ty(t), lower_mutability(m), lower_expr(e))
+ hir::ItemStatic(lower_ty(_lctx, t),
+ lower_mutability(_lctx, m),
+ lower_expr(_lctx, e))
}
ItemConst(ref t, ref e) => {
- hir::ItemConst(lower_ty(t), lower_expr(e))
+ hir::ItemConst(lower_ty(_lctx, t), lower_expr(_lctx, e))
}
ItemFn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
- hir::ItemFn(
- lower_fn_decl(decl),
- lower_unsafety(unsafety),
- lower_constness(constness),
- abi,
- lower_generics(generics),
- lower_block(body)
- )
+ hir::ItemFn(lower_fn_decl(_lctx, decl),
+ lower_unsafety(_lctx, unsafety),
+ lower_constness(_lctx, constness),
+ abi,
+ lower_generics(_lctx, generics),
+ lower_block(_lctx, body))
}
- ItemMod(ref m) => hir::ItemMod(lower_mod(m)),
- ItemForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(nm)),
+ ItemMod(ref m) => hir::ItemMod(lower_mod(_lctx, m)),
+ ItemForeignMod(ref nm) => hir::ItemForeignMod(lower_foreign_mod(_lctx, nm)),
ItemTy(ref t, ref generics) => {
- hir::ItemTy(lower_ty(t), lower_generics(generics))
+ hir::ItemTy(lower_ty(_lctx, t), lower_generics(_lctx, generics))
}
ItemEnum(ref enum_definition, ref generics) => {
- hir::ItemEnum(
- hir::EnumDef {
- variants: enum_definition.variants.iter().map(|x| lower_variant(x)).collect(),
- },
- lower_generics(generics))
+ hir::ItemEnum(hir::EnumDef {
+ variants: enum_definition.variants
+ .iter()
+ .map(|x| lower_variant(_lctx, x))
+ .collect(),
+ },
+ lower_generics(_lctx, generics))
}
ItemStruct(ref struct_def, ref generics) => {
- let struct_def = lower_struct_def(struct_def);
- hir::ItemStruct(struct_def, lower_generics(generics))
+ let struct_def = lower_variant_data(_lctx, struct_def);
+ hir::ItemStruct(struct_def, lower_generics(_lctx, generics))
}
ItemDefaultImpl(unsafety, ref trait_ref) => {
- hir::ItemDefaultImpl(lower_unsafety(unsafety), lower_trait_ref(trait_ref))
+ hir::ItemDefaultImpl(lower_unsafety(_lctx, unsafety),
+ lower_trait_ref(_lctx, trait_ref))
}
ItemImpl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
- let new_impl_items = impl_items.iter().map(|item| lower_impl_item(item)).collect();
- let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(trait_ref));
- hir::ItemImpl(lower_unsafety(unsafety),
- lower_impl_polarity(polarity),
- lower_generics(generics),
+ let new_impl_items = impl_items.iter()
+ .map(|item| lower_impl_item(_lctx, item))
+ .collect();
+ let ifce = ifce.as_ref().map(|trait_ref| lower_trait_ref(_lctx, trait_ref));
+ hir::ItemImpl(lower_unsafety(_lctx, unsafety),
+ lower_impl_polarity(_lctx, polarity),
+ lower_generics(_lctx, generics),
ifce,
- lower_ty(ty),
+ lower_ty(_lctx, ty),
new_impl_items)
}
ItemTrait(unsafety, ref generics, ref bounds, ref items) => {
- let bounds = lower_bounds(bounds);
- let items = items.iter().map(|item| lower_trait_item(item)).collect();
- hir::ItemTrait(lower_unsafety(unsafety),
- lower_generics(generics),
+ let bounds = lower_bounds(_lctx, bounds);
+ let items = items.iter().map(|item| lower_trait_item(_lctx, item)).collect();
+ hir::ItemTrait(lower_unsafety(_lctx, unsafety),
+ lower_generics(_lctx, generics),
bounds,
items)
}
}
}
-pub fn lower_trait_item(i: &TraitItem) -> P<hir::TraitItem> {
+pub fn lower_trait_item(_lctx: &LoweringContext, i: &TraitItem) -> P<hir::TraitItem> {
P(hir::TraitItem {
- id: i.id,
- ident: i.ident,
- attrs: lower_attrs(&i.attrs),
- node: match i.node {
+ id: i.id,
+ name: i.ident.name,
+ attrs: i.attrs.clone(),
+ node: match i.node {
ConstTraitItem(ref ty, ref default) => {
- hir::ConstTraitItem(lower_ty(ty),
- default.as_ref().map(|x| lower_expr(x)))
+ hir::ConstTraitItem(lower_ty(_lctx, ty),
+ default.as_ref().map(|x| lower_expr(_lctx, x)))
}
MethodTraitItem(ref sig, ref body) => {
- hir::MethodTraitItem(lower_method_sig(sig),
- body.as_ref().map(|x| lower_block(x)))
+ hir::MethodTraitItem(lower_method_sig(_lctx, sig),
+ body.as_ref().map(|x| lower_block(_lctx, x)))
}
TypeTraitItem(ref bounds, ref default) => {
- hir::TypeTraitItem(lower_bounds(bounds),
- default.as_ref().map(|x| lower_ty(x)))
+ hir::TypeTraitItem(lower_bounds(_lctx, bounds),
+ default.as_ref().map(|x| lower_ty(_lctx, x)))
}
},
- span: i.span,
- })
+ span: i.span,
+ })
}
-pub fn lower_impl_item(i: &ImplItem) -> P<hir::ImplItem> {
+pub fn lower_impl_item(_lctx: &LoweringContext, i: &ImplItem) -> P<hir::ImplItem> {
P(hir::ImplItem {
- id: i.id,
- ident: i.ident,
- attrs: lower_attrs(&i.attrs),
- vis: lower_visibility(i.vis),
- node: match i.node {
+ id: i.id,
+ name: i.ident.name,
+ attrs: i.attrs.clone(),
+ vis: lower_visibility(_lctx, i.vis),
+ node: match i.node {
ConstImplItem(ref ty, ref expr) => {
- hir::ConstImplItem(lower_ty(ty), lower_expr(expr))
+ hir::ConstImplItem(lower_ty(_lctx, ty), lower_expr(_lctx, expr))
}
MethodImplItem(ref sig, ref body) => {
- hir::MethodImplItem(lower_method_sig(sig),
- lower_block(body))
+ hir::MethodImplItem(lower_method_sig(_lctx, sig),
+ lower_block(_lctx, body))
}
- TypeImplItem(ref ty) => hir::TypeImplItem(lower_ty(ty)),
+ TypeImplItem(ref ty) => hir::TypeImplItem(lower_ty(_lctx, ty)),
MacImplItem(..) => panic!("Shouldn't exist any more"),
},
- span: i.span,
- })
+ span: i.span,
+ })
}
-pub fn lower_mod(m: &Mod) -> hir::Mod {
- hir::Mod { inner: m.inner, items: m.items.iter().map(|x| lower_item(x)).collect() }
+pub fn lower_mod(_lctx: &LoweringContext, m: &Mod) -> hir::Mod {
+ hir::Mod {
+ inner: m.inner,
+ items: m.items.iter().map(|x| lower_item(_lctx, x)).collect(),
+ }
}
-pub fn lower_crate(c: &Crate) -> hir::Crate {
- let config = lower_meta_items(&c.config);
-
+pub fn lower_crate(_lctx: &LoweringContext, c: &Crate) -> hir::Crate {
hir::Crate {
- module: lower_mod(&c.module),
- attrs: lower_attrs(&c.attrs),
- config: config,
+ module: lower_mod(_lctx, &c.module),
+ attrs: c.attrs.clone(),
+ config: c.config.clone(),
span: c.span,
- exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(m)).collect(),
+ exported_macros: c.exported_macros.iter().map(|m| lower_macro_def(_lctx, m)).collect(),
}
}
-pub fn lower_macro_def(m: &MacroDef) -> hir::MacroDef {
+pub fn lower_macro_def(_lctx: &LoweringContext, m: &MacroDef) -> hir::MacroDef {
hir::MacroDef {
- ident: m.ident,
- attrs: m.attrs.iter().map(|a| lower_attribute(a)).collect(),
+ name: m.ident.name,
+ attrs: m.attrs.clone(),
id: m.id,
span: m.span,
- imported_from: m.imported_from,
+ imported_from: m.imported_from.map(|x| x.name),
export: m.export,
use_locally: m.use_locally,
allow_internal_unstable: m.allow_internal_unstable,
}
// fold one item into possibly many items
-pub fn lower_item(i: &Item) -> P<hir::Item> {
- P(lower_item_simple(i))
+pub fn lower_item(_lctx: &LoweringContext, i: &Item) -> P<hir::Item> {
+ P(lower_item_simple(_lctx, i))
}
// fold one item into exactly one item
-pub fn lower_item_simple(i: &Item) -> hir::Item {
- let node = lower_item_underscore(&i.node);
+pub fn lower_item_simple(_lctx: &LoweringContext, i: &Item) -> hir::Item {
+ let node = lower_item_underscore(_lctx, &i.node);
hir::Item {
id: i.id,
- ident: i.ident,
- attrs: lower_attrs(&i.attrs),
+ name: i.ident.name,
+ attrs: i.attrs.clone(),
node: node,
- vis: lower_visibility(i.vis),
+ vis: lower_visibility(_lctx, i.vis),
span: i.span,
}
}
-pub fn lower_foreign_item(i: &ForeignItem) -> P<hir::ForeignItem> {
+pub fn lower_foreign_item(_lctx: &LoweringContext, i: &ForeignItem) -> P<hir::ForeignItem> {
P(hir::ForeignItem {
- id: i.id,
- ident: i.ident,
- attrs: lower_attrs(&i.attrs),
- node: match i.node {
+ id: i.id,
+ name: i.ident.name,
+ attrs: i.attrs.clone(),
+ node: match i.node {
ForeignItemFn(ref fdec, ref generics) => {
- hir::ForeignItemFn(lower_fn_decl(fdec), lower_generics(generics))
+ hir::ForeignItemFn(lower_fn_decl(_lctx, fdec),
+ lower_generics(_lctx, generics))
}
ForeignItemStatic(ref t, m) => {
- hir::ForeignItemStatic(lower_ty(t), m)
+ hir::ForeignItemStatic(lower_ty(_lctx, t), m)
}
},
- vis: lower_visibility(i.vis),
- span: i.span,
- })
+ vis: lower_visibility(_lctx, i.vis),
+ span: i.span,
+ })
}
-pub fn lower_method_sig(sig: &MethodSig) -> hir::MethodSig {
+pub fn lower_method_sig(_lctx: &LoweringContext, sig: &MethodSig) -> hir::MethodSig {
hir::MethodSig {
- generics: lower_generics(&sig.generics),
+ generics: lower_generics(_lctx, &sig.generics),
abi: sig.abi,
- explicit_self: lower_explicit_self(&sig.explicit_self),
- unsafety: lower_unsafety(sig.unsafety),
- constness: lower_constness(sig.constness),
- decl: lower_fn_decl(&sig.decl),
+ explicit_self: lower_explicit_self(_lctx, &sig.explicit_self),
+ unsafety: lower_unsafety(_lctx, sig.unsafety),
+ constness: lower_constness(_lctx, sig.constness),
+ decl: lower_fn_decl(_lctx, &sig.decl),
}
}
-pub fn lower_unsafety(u: Unsafety) -> hir::Unsafety {
+pub fn lower_unsafety(_lctx: &LoweringContext, u: Unsafety) -> hir::Unsafety {
match u {
Unsafety::Unsafe => hir::Unsafety::Unsafe,
Unsafety::Normal => hir::Unsafety::Normal,
}
}
-pub fn lower_constness(c: Constness) -> hir::Constness {
+pub fn lower_constness(_lctx: &LoweringContext, c: Constness) -> hir::Constness {
match c {
Constness::Const => hir::Constness::Const,
Constness::NotConst => hir::Constness::NotConst,
}
}
-pub fn lower_lit(l: &Lit) -> hir::Lit {
- Spanned {
- node: match l.node {
- LitStr(ref i, s) => hir::LitStr(i.clone(), lower_string_style(s)),
- LitByteStr(ref b) => hir::LitByteStr(b.clone()),
- LitByte(u) => hir::LitByte(u),
- LitChar(c) => hir::LitChar(c),
- LitInt(u, ref t) => hir::LitInt(u, lower_lit_int_type(t)),
- LitFloat(ref i, t) => hir::LitFloat(i.clone(), lower_float_ty(t)),
- LitFloatUnsuffixed(ref i) => hir::LitFloatUnsuffixed(i.clone()),
- LitBool(b) => hir::LitBool(b),
- },
- span: l.span,
- }
-}
-
-pub fn unlower_lit(l: &hir::Lit) -> Lit {
- Spanned {
- node: match l.node {
- hir::LitStr(ref i, s) => LitStr(i.clone(), unlower_string_style(s)),
- hir::LitByteStr(ref b) => LitByteStr(b.clone()),
- hir::LitByte(u) => LitByte(u),
- hir::LitChar(c) => LitChar(c),
- hir::LitInt(u, ref t) => LitInt(u, unlower_lit_int_type(t)),
- hir::LitFloat(ref i, t) => LitFloat(i.clone(), unlower_float_ty(t)),
- hir::LitFloatUnsuffixed(ref i) => LitFloatUnsuffixed(i.clone()),
- hir::LitBool(b) => LitBool(b),
- },
- span: l.span,
- }
-}
-pub fn lower_unop(u: UnOp) -> hir::UnOp {
+pub fn lower_unop(_lctx: &LoweringContext, u: UnOp) -> hir::UnOp {
match u {
- UnUniq => hir::UnUniq,
UnDeref => hir::UnDeref,
UnNot => hir::UnNot,
UnNeg => hir::UnNeg,
}
}
-pub fn lower_binop(b: BinOp) -> hir::BinOp {
+pub fn lower_binop(_lctx: &LoweringContext, b: BinOp) -> hir::BinOp {
Spanned {
node: match b.node {
BiAdd => hir::BiAdd,
}
}
-pub fn lower_pat(p: &Pat) -> P<hir::Pat> {
+pub fn lower_pat(_lctx: &LoweringContext, p: &Pat) -> P<hir::Pat> {
P(hir::Pat {
- id: p.id,
- node: match p.node {
- PatWild(k) => hir::PatWild(lower_pat_wild_kind(k)),
+ id: p.id,
+ node: match p.node {
+ PatWild(k) => hir::PatWild(lower_pat_wild_kind(_lctx, k)),
PatIdent(ref binding_mode, pth1, ref sub) => {
- hir::PatIdent(lower_binding_mode(binding_mode),
- pth1,
- sub.as_ref().map(|x| lower_pat(x)))
+ hir::PatIdent(lower_binding_mode(_lctx, binding_mode),
+ pth1,
+ sub.as_ref().map(|x| lower_pat(_lctx, x)))
}
- PatLit(ref e) => hir::PatLit(lower_expr(e)),
+ PatLit(ref e) => hir::PatLit(lower_expr(_lctx, e)),
PatEnum(ref pth, ref pats) => {
- hir::PatEnum(lower_path(pth),
- pats.as_ref().map(|pats| pats.iter().map(|x| lower_pat(x)).collect()))
+ hir::PatEnum(lower_path(_lctx, pth),
+ pats.as_ref()
+ .map(|pats| pats.iter().map(|x| lower_pat(_lctx, x)).collect()))
}
PatQPath(ref qself, ref pth) => {
let qself = hir::QSelf {
- ty: lower_ty(&qself.ty),
+ ty: lower_ty(_lctx, &qself.ty),
position: qself.position,
};
- hir::PatQPath(qself, lower_path(pth))
+ hir::PatQPath(qself, lower_path(_lctx, pth))
}
PatStruct(ref pth, ref fields, etc) => {
- let pth = lower_path(pth);
- let fs = fields.iter().map(|f| {
- Spanned { span: f.span,
- node: hir::FieldPat {
- ident: f.node.ident,
- pat: lower_pat(&f.node.pat),
- is_shorthand: f.node.is_shorthand,
- }}
- }).collect();
+ let pth = lower_path(_lctx, pth);
+ let fs = fields.iter()
+ .map(|f| {
+ Spanned {
+ span: f.span,
+ node: hir::FieldPat {
+ name: f.node.ident.name,
+ pat: lower_pat(_lctx, &f.node.pat),
+ is_shorthand: f.node.is_shorthand,
+ },
+ }
+ })
+ .collect();
hir::PatStruct(pth, fs, etc)
}
- PatTup(ref elts) => hir::PatTup(elts.iter().map(|x| lower_pat(x)).collect()),
- PatBox(ref inner) => hir::PatBox(lower_pat(inner)),
- PatRegion(ref inner, mutbl) => hir::PatRegion(lower_pat(inner),
- lower_mutability(mutbl)),
+ PatTup(ref elts) => hir::PatTup(elts.iter().map(|x| lower_pat(_lctx, x)).collect()),
+ PatBox(ref inner) => hir::PatBox(lower_pat(_lctx, inner)),
+ PatRegion(ref inner, mutbl) => hir::PatRegion(lower_pat(_lctx, inner),
+ lower_mutability(_lctx, mutbl)),
PatRange(ref e1, ref e2) => {
- hir::PatRange(lower_expr(e1), lower_expr(e2))
- },
+ hir::PatRange(lower_expr(_lctx, e1), lower_expr(_lctx, e2))
+ }
PatVec(ref before, ref slice, ref after) => {
- hir::PatVec(before.iter().map(|x| lower_pat(x)).collect(),
- slice.as_ref().map(|x| lower_pat(x)),
- after.iter().map(|x| lower_pat(x)).collect())
+ hir::PatVec(before.iter().map(|x| lower_pat(_lctx, x)).collect(),
+ slice.as_ref().map(|x| lower_pat(_lctx, x)),
+ after.iter().map(|x| lower_pat(_lctx, x)).collect())
}
PatMac(_) => panic!("Shouldn't exist here"),
},
- span: p.span,
- })
+ span: p.span,
+ })
+}
+
+// RAII utility for setting and unsetting the cached id.
+struct CachedIdSetter<'a> {
+ reset: bool,
+ lctx: &'a LoweringContext<'a>,
+}
+
+impl<'a> CachedIdSetter<'a> {
+ fn new(lctx: &'a LoweringContext, expr_id: NodeId) -> CachedIdSetter<'a> {
+ // Only reset the id if it was previously 0, i.e., was not cached.
+ // If it was cached, we are in a nested node, but our id count will
+ // still count towards the parent's count.
+ let reset_cached_id = lctx.cached_id.get() == 0;
+
+ let id_cache: &mut HashMap<_, _> = &mut lctx.id_cache.borrow_mut();
+
+ if id_cache.contains_key(&expr_id) {
+ let cached_id = lctx.cached_id.get();
+ if cached_id == 0 {
+ // We're entering a node where we need to track ids, but are not
+ // yet tracking.
+ lctx.cached_id.set(id_cache[&expr_id]);
+ lctx.gensym_key.set(id_cache[&expr_id]);
+ } else {
+ // We're already tracking - check that the tracked id is the same
+ // as the expected id.
+ assert!(cached_id == id_cache[&expr_id], "id mismatch");
+ }
+ } else {
+ let next_id = lctx.id_assigner.peek_node_id();
+ id_cache.insert(expr_id, next_id);
+ lctx.gensym_key.set(next_id);
+ }
+
+ CachedIdSetter {
+ reset: reset_cached_id,
+ lctx: lctx,
+ }
+ }
}
-pub fn lower_expr(e: &Expr) -> P<hir::Expr> {
+impl<'a> Drop for CachedIdSetter<'a> {
+ fn drop(&mut self) {
+ if self.reset {
+ self.lctx.cached_id.set(0);
+ self.lctx.gensym_key.set(0);
+ }
+ }
+}
+
+pub fn lower_expr(lctx: &LoweringContext, e: &Expr) -> P<hir::Expr> {
P(hir::Expr {
- id: e.id,
- node: match e.node {
- ExprBox(ref p, ref e) => {
- hir::ExprBox(p.as_ref().map(|e| lower_expr(e)), lower_expr(e))
- }
- ExprVec(ref exprs) => {
- hir::ExprVec(exprs.iter().map(|x| lower_expr(x)).collect())
- }
- ExprRepeat(ref expr, ref count) => {
- hir::ExprRepeat(lower_expr(expr), lower_expr(count))
- }
- ExprTup(ref elts) => hir::ExprTup(elts.iter().map(|x| lower_expr(x)).collect()),
- ExprCall(ref f, ref args) => {
- hir::ExprCall(lower_expr(f),
- args.iter().map(|x| lower_expr(x)).collect())
- }
- ExprMethodCall(i, ref tps, ref args) => {
- hir::ExprMethodCall(
- i,
- tps.iter().map(|x| lower_ty(x)).collect(),
- args.iter().map(|x| lower_expr(x)).collect())
- }
- ExprBinary(binop, ref lhs, ref rhs) => {
- hir::ExprBinary(lower_binop(binop),
- lower_expr(lhs),
- lower_expr(rhs))
- }
- ExprUnary(op, ref ohs) => {
- hir::ExprUnary(lower_unop(op), lower_expr(ohs))
- }
- ExprLit(ref l) => hir::ExprLit(P(lower_lit(l))),
- ExprCast(ref expr, ref ty) => {
- hir::ExprCast(lower_expr(expr), lower_ty(ty))
- }
- ExprAddrOf(m, ref ohs) => hir::ExprAddrOf(lower_mutability(m), lower_expr(ohs)),
- ExprIf(ref cond, ref tr, ref fl) => {
- hir::ExprIf(lower_expr(cond),
- lower_block(tr),
- fl.as_ref().map(|x| lower_expr(x)))
- }
- ExprWhile(ref cond, ref body, opt_ident) => {
- hir::ExprWhile(lower_expr(cond),
- lower_block(body),
- opt_ident)
- }
- ExprLoop(ref body, opt_ident) => {
- hir::ExprLoop(lower_block(body),
- opt_ident)
- }
- ExprMatch(ref expr, ref arms, ref source) => {
- hir::ExprMatch(lower_expr(expr),
- arms.iter().map(|x| lower_arm(x)).collect(),
- lower_match_source(source))
- }
- ExprClosure(capture_clause, ref decl, ref body) => {
- hir::ExprClosure(lower_capture_clause(capture_clause),
- lower_fn_decl(decl),
- lower_block(body))
- }
- ExprBlock(ref blk) => hir::ExprBlock(lower_block(blk)),
- ExprAssign(ref el, ref er) => {
- hir::ExprAssign(lower_expr(el), lower_expr(er))
- }
- ExprAssignOp(op, ref el, ref er) => {
- hir::ExprAssignOp(lower_binop(op),
- lower_expr(el),
- lower_expr(er))
- }
- ExprField(ref el, ident) => {
- hir::ExprField(lower_expr(el), ident)
- }
- ExprTupField(ref el, ident) => {
- hir::ExprTupField(lower_expr(el), ident)
- }
- ExprIndex(ref el, ref er) => {
- hir::ExprIndex(lower_expr(el), lower_expr(er))
- }
- ExprRange(ref e1, ref e2) => {
- hir::ExprRange(e1.as_ref().map(|x| lower_expr(x)),
- e2.as_ref().map(|x| lower_expr(x)))
- }
- ExprPath(ref qself, ref path) => {
- let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
- hir::QSelf {
- ty: lower_ty(ty),
- position: position
+ id: e.id,
+ node: match e.node {
+ // Issue #22181:
+ // Eventually a desugaring for `box EXPR`
+ // (similar to the desugaring above for `in PLACE BLOCK`)
+ // should go here, desugaring
+ //
+ // to:
+ //
+ // let mut place = BoxPlace::make_place();
+ // let raw_place = Place::pointer(&mut place);
+ // let value = $value;
+ // unsafe {
+ // ::std::ptr::write(raw_place, value);
+ // Boxed::finalize(place)
+ // }
+ //
+ // But for now there are type-inference issues doing that.
+ ExprBox(ref e) => {
+ hir::ExprBox(lower_expr(lctx, e))
+ }
+
+ // Desugar ExprBox: `in (PLACE) EXPR`
+ ExprInPlace(ref placer, ref value_expr) => {
+ // to:
+ //
+ // let p = PLACE;
+ // let mut place = Placer::make_place(p);
+ // let raw_place = Place::pointer(&mut place);
+ // push_unsafe!({
+ // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
+ // InPlace::finalize(place)
+ // })
+ let _old_cached = CachedIdSetter::new(lctx, e.id);
+
+ let placer_expr = lower_expr(lctx, placer);
+ let value_expr = lower_expr(lctx, value_expr);
+
+ let placer_ident = lctx.str_to_ident("placer");
+ let agent_ident = lctx.str_to_ident("place");
+ let p_ptr_ident = lctx.str_to_ident("p_ptr");
+
+ let make_place = ["ops", "Placer", "make_place"];
+ let place_pointer = ["ops", "Place", "pointer"];
+ let move_val_init = ["intrinsics", "move_val_init"];
+ let inplace_finalize = ["ops", "InPlace", "finalize"];
+
+ let make_call = |lctx, p, args| {
+ let path = core_path(lctx, e.span, p);
+ let path = expr_path(lctx, path);
+ expr_call(lctx, e.span, path, args)
+ };
+
+ let mk_stmt_let = |lctx, bind, expr| stmt_let(lctx, e.span, false, bind, expr);
+ let mk_stmt_let_mut = |lctx, bind, expr| stmt_let(lctx, e.span, true, bind, expr);
+
+ // let placer = <placer_expr> ;
+ let s1 = mk_stmt_let(lctx,
+ placer_ident,
+ signal_block_expr(lctx,
+ vec![],
+ placer_expr,
+ e.span,
+ hir::PopUnstableBlock));
+
+ // let mut place = Placer::make_place(placer);
+ let s2 = {
+ let call = make_call(lctx,
+ &make_place,
+ vec![expr_ident(lctx, e.span, placer_ident)]);
+ mk_stmt_let_mut(lctx, agent_ident, call)
+ };
+
+ // let p_ptr = Place::pointer(&mut place);
+ let s3 = {
+ let args = vec![expr_mut_addr_of(lctx,
+ e.span,
+ expr_ident(lctx, e.span, agent_ident))];
+ let call = make_call(lctx, &place_pointer, args);
+ mk_stmt_let(lctx, p_ptr_ident, call)
+ };
+
+ // pop_unsafe!(EXPR));
+ let pop_unsafe_expr =
+ signal_block_expr(lctx,
+ vec![],
+ signal_block_expr(lctx,
+ vec![],
+ value_expr,
+ e.span,
+ hir::PopUnstableBlock),
+ e.span,
+ hir::PopUnsafeBlock(hir::CompilerGenerated));
+
+ // push_unsafe!({
+ // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
+ // InPlace::finalize(place)
+ // })
+ let expr = {
+ let call_move_val_init = hir::StmtSemi(make_call(lctx,
+ &move_val_init,
+ vec![expr_ident(lctx, e.span, p_ptr_ident),
+ pop_unsafe_expr]),
+ lctx.next_id());
+ let call_move_val_init = respan(e.span, call_move_val_init);
+
+ let call = make_call(lctx,
+ &inplace_finalize,
+ vec![expr_ident(lctx, e.span, agent_ident)]);
+ signal_block_expr(lctx,
+ vec![P(call_move_val_init)],
+ call,
+ e.span,
+ hir::PushUnsafeBlock(hir::CompilerGenerated))
+ };
+
+ return signal_block_expr(lctx,
+ vec![s1, s2, s3],
+ expr,
+ e.span,
+ hir::PushUnstableBlock);
+ }
+
+ ExprVec(ref exprs) => {
+ hir::ExprVec(exprs.iter().map(|x| lower_expr(lctx, x)).collect())
+ }
+ ExprRepeat(ref expr, ref count) => {
+ hir::ExprRepeat(lower_expr(lctx, expr), lower_expr(lctx, count))
+ }
+ ExprTup(ref elts) => {
+ hir::ExprTup(elts.iter().map(|x| lower_expr(lctx, x)).collect())
+ }
+ ExprCall(ref f, ref args) => {
+ hir::ExprCall(lower_expr(lctx, f),
+ args.iter().map(|x| lower_expr(lctx, x)).collect())
+ }
+ ExprMethodCall(i, ref tps, ref args) => {
+ hir::ExprMethodCall(respan(i.span, i.node.name),
+ tps.iter().map(|x| lower_ty(lctx, x)).collect(),
+ args.iter().map(|x| lower_expr(lctx, x)).collect())
+ }
+ ExprBinary(binop, ref lhs, ref rhs) => {
+ hir::ExprBinary(lower_binop(lctx, binop),
+ lower_expr(lctx, lhs),
+ lower_expr(lctx, rhs))
+ }
+ ExprUnary(op, ref ohs) => {
+ hir::ExprUnary(lower_unop(lctx, op), lower_expr(lctx, ohs))
+ }
+ ExprLit(ref l) => hir::ExprLit(P((**l).clone())),
+ ExprCast(ref expr, ref ty) => {
+ hir::ExprCast(lower_expr(lctx, expr), lower_ty(lctx, ty))
+ }
+ ExprAddrOf(m, ref ohs) => {
+ hir::ExprAddrOf(lower_mutability(lctx, m), lower_expr(lctx, ohs))
+ }
+ // More complicated than you might expect because the else branch
+ // might be `if let`.
+ ExprIf(ref cond, ref blk, ref else_opt) => {
+ let else_opt = else_opt.as_ref().map(|els| {
+ match els.node {
+ ExprIfLet(..) => {
+ let _old_cached = CachedIdSetter::new(lctx, e.id);
+ // wrap the if-let expr in a block
+ let span = els.span;
+ let blk = P(hir::Block {
+ stmts: vec![],
+ expr: Some(lower_expr(lctx, els)),
+ id: lctx.next_id(),
+ rules: hir::DefaultBlock,
+ span: span,
+ });
+ expr_block(lctx, blk)
}
- });
- hir::ExprPath(qself, lower_path(path))
- }
- ExprBreak(opt_ident) => hir::ExprBreak(opt_ident),
- ExprAgain(opt_ident) => hir::ExprAgain(opt_ident),
- ExprRet(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(x))),
- ExprInlineAsm(InlineAsm {
+ _ => lower_expr(lctx, els),
+ }
+ });
+
+ hir::ExprIf(lower_expr(lctx, cond),
+ lower_block(lctx, blk),
+ else_opt)
+ }
+ ExprWhile(ref cond, ref body, opt_ident) => {
+ hir::ExprWhile(lower_expr(lctx, cond),
+ lower_block(lctx, body),
+ opt_ident)
+ }
+ ExprLoop(ref body, opt_ident) => {
+ hir::ExprLoop(lower_block(lctx, body), opt_ident)
+ }
+ ExprMatch(ref expr, ref arms) => {
+ hir::ExprMatch(lower_expr(lctx, expr),
+ arms.iter().map(|x| lower_arm(lctx, x)).collect(),
+ hir::MatchSource::Normal)
+ }
+ ExprClosure(capture_clause, ref decl, ref body) => {
+ hir::ExprClosure(lower_capture_clause(lctx, capture_clause),
+ lower_fn_decl(lctx, decl),
+ lower_block(lctx, body))
+ }
+ ExprBlock(ref blk) => hir::ExprBlock(lower_block(lctx, blk)),
+ ExprAssign(ref el, ref er) => {
+ hir::ExprAssign(lower_expr(lctx, el), lower_expr(lctx, er))
+ }
+ ExprAssignOp(op, ref el, ref er) => {
+ hir::ExprAssignOp(lower_binop(lctx, op),
+ lower_expr(lctx, el),
+ lower_expr(lctx, er))
+ }
+ ExprField(ref el, ident) => {
+ hir::ExprField(lower_expr(lctx, el),
+ respan(ident.span, ident.node.name))
+ }
+ ExprTupField(ref el, ident) => {
+ hir::ExprTupField(lower_expr(lctx, el), ident)
+ }
+ ExprIndex(ref el, ref er) => {
+ hir::ExprIndex(lower_expr(lctx, el), lower_expr(lctx, er))
+ }
+ ExprRange(ref e1, ref e2) => {
+ hir::ExprRange(e1.as_ref().map(|x| lower_expr(lctx, x)),
+ e2.as_ref().map(|x| lower_expr(lctx, x)))
+ }
+ ExprPath(ref qself, ref path) => {
+ let qself = qself.as_ref().map(|&QSelf { ref ty, position }| {
+ hir::QSelf {
+ ty: lower_ty(lctx, ty),
+ position: position,
+ }
+ });
+ hir::ExprPath(qself, lower_path(lctx, path))
+ }
+ ExprBreak(opt_ident) => hir::ExprBreak(opt_ident),
+ ExprAgain(opt_ident) => hir::ExprAgain(opt_ident),
+ ExprRet(ref e) => hir::ExprRet(e.as_ref().map(|x| lower_expr(lctx, x))),
+ ExprInlineAsm(InlineAsm {
ref inputs,
ref outputs,
ref asm,
dialect,
expn_id,
}) => hir::ExprInlineAsm(hir::InlineAsm {
- inputs: inputs.iter().map(|&(ref c, ref input)| {
- (c.clone(), lower_expr(input))
- }).collect(),
- outputs: outputs.iter().map(|&(ref c, ref out, ref is_rw)| {
- (c.clone(), lower_expr(out), *is_rw)
- }).collect(),
- asm: asm.clone(),
- asm_str_style: lower_string_style(asm_str_style),
- clobbers: clobbers.clone(),
- volatile: volatile,
- alignstack: alignstack,
- dialect: lower_asm_dialect(dialect),
- expn_id: expn_id,
- }),
- ExprStruct(ref path, ref fields, ref maybe_expr) => {
- hir::ExprStruct(lower_path(path),
- fields.iter().map(|x| lower_field(x)).collect(),
- maybe_expr.as_ref().map(|x| lower_expr(x)))
- },
- ExprParen(ref ex) => hir::ExprParen(lower_expr(ex)),
- ExprIfLet(..) |
- ExprWhileLet(..) |
- ExprForLoop(..) |
- ExprMac(_) => panic!("Shouldn't exist here"),
- },
- span: e.span,
- })
-}
-
-pub fn lower_stmt(s: &Stmt) -> P<hir::Stmt> {
+ inputs: inputs.iter()
+ .map(|&(ref c, ref input)| (c.clone(), lower_expr(lctx, input)))
+ .collect(),
+ outputs: outputs.iter()
+ .map(|&(ref c, ref out, ref is_rw)| {
+ (c.clone(), lower_expr(lctx, out), *is_rw)
+ })
+ .collect(),
+ asm: asm.clone(),
+ asm_str_style: asm_str_style,
+ clobbers: clobbers.clone(),
+ volatile: volatile,
+ alignstack: alignstack,
+ dialect: dialect,
+ expn_id: expn_id,
+ }),
+ ExprStruct(ref path, ref fields, ref maybe_expr) => {
+ hir::ExprStruct(lower_path(lctx, path),
+ fields.iter().map(|x| lower_field(lctx, x)).collect(),
+ maybe_expr.as_ref().map(|x| lower_expr(lctx, x)))
+ }
+ ExprParen(ref ex) => {
+ return lower_expr(lctx, ex);
+ }
+
+ // Desugar ExprIfLet
+ // From: `if let <pat> = <sub_expr> <body> [<else_opt>]`
+ ExprIfLet(ref pat, ref sub_expr, ref body, ref else_opt) => {
+ // to:
+ //
+ // match <sub_expr> {
+ // <pat> => <body>,
+ // [_ if <else_opt_if_cond> => <else_opt_if_body>,]
+ // _ => [<else_opt> | ()]
+ // }
+
+ let _old_cached = CachedIdSetter::new(lctx, e.id);
+
+ // `<pat> => <body>`
+ let pat_arm = {
+ let body_expr = expr_block(lctx, lower_block(lctx, body));
+ arm(vec![lower_pat(lctx, pat)], body_expr)
+ };
+
+ // `[_ if <else_opt_if_cond> => <else_opt_if_body>,]`
+ let mut else_opt = else_opt.as_ref().map(|e| lower_expr(lctx, e));
+ let else_if_arms = {
+ let mut arms = vec![];
+ loop {
+ let else_opt_continue = else_opt.and_then(|els| {
+ els.and_then(|els| {
+ match els.node {
+ // else if
+ hir::ExprIf(cond, then, else_opt) => {
+ let pat_under = pat_wild(lctx, e.span);
+ arms.push(hir::Arm {
+ attrs: vec![],
+ pats: vec![pat_under],
+ guard: Some(cond),
+ body: expr_block(lctx, then),
+ });
+ else_opt.map(|else_opt| (else_opt, true))
+ }
+ _ => Some((P(els), false)),
+ }
+ })
+ });
+ match else_opt_continue {
+ Some((e, true)) => {
+ else_opt = Some(e);
+ }
+ Some((e, false)) => {
+ else_opt = Some(e);
+ break;
+ }
+ None => {
+ else_opt = None;
+ break;
+ }
+ }
+ }
+ arms
+ };
+
+ let contains_else_clause = else_opt.is_some();
+
+ // `_ => [<else_opt> | ()]`
+ let else_arm = {
+ let pat_under = pat_wild(lctx, e.span);
+ let else_expr = else_opt.unwrap_or_else(|| expr_tuple(lctx, e.span, vec![]));
+ arm(vec![pat_under], else_expr)
+ };
+
+ let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
+ arms.push(pat_arm);
+ arms.extend(else_if_arms);
+ arms.push(else_arm);
+
+ let match_expr = expr(lctx,
+ e.span,
+ hir::ExprMatch(lower_expr(lctx, sub_expr),
+ arms,
+ hir::MatchSource::IfLetDesugar {
+ contains_else_clause: contains_else_clause,
+ }));
+ return match_expr;
+ }
+
+ // Desugar ExprWhileLet
+ // From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
+ ExprWhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
+ // to:
+ //
+ // [opt_ident]: loop {
+ // match <sub_expr> {
+ // <pat> => <body>,
+ // _ => break
+ // }
+ // }
+
+ let _old_cached = CachedIdSetter::new(lctx, e.id);
+
+ // `<pat> => <body>`
+ let pat_arm = {
+ let body_expr = expr_block(lctx, lower_block(lctx, body));
+ arm(vec![lower_pat(lctx, pat)], body_expr)
+ };
+
+ // `_ => break`
+ let break_arm = {
+ let pat_under = pat_wild(lctx, e.span);
+ let break_expr = expr_break(lctx, e.span);
+ arm(vec![pat_under], break_expr)
+ };
+
+ // `match <sub_expr> { ... }`
+ let arms = vec![pat_arm, break_arm];
+ let match_expr = expr(lctx,
+ e.span,
+ hir::ExprMatch(lower_expr(lctx, sub_expr),
+ arms,
+ hir::MatchSource::WhileLetDesugar));
+
+ // `[opt_ident]: loop { ... }`
+ let loop_block = block_expr(lctx, match_expr);
+ return expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident));
+ }
+
+ // Desugar ExprForLoop
+ // From: `[opt_ident]: for <pat> in <head> <body>`
+ ExprForLoop(ref pat, ref head, ref body, opt_ident) => {
+ // to:
+ //
+ // {
+ // let result = match ::std::iter::IntoIterator::into_iter(<head>) {
+ // mut iter => {
+ // [opt_ident]: loop {
+ // match ::std::iter::Iterator::next(&mut iter) {
+ // ::std::option::Option::Some(<pat>) => <body>,
+ // ::std::option::Option::None => break
+ // }
+ // }
+ // }
+ // };
+ // result
+ // }
+
+ let _old_cached = CachedIdSetter::new(lctx, e.id);
+
+ // expand <head>
+ let head = lower_expr(lctx, head);
+
+ let iter = lctx.str_to_ident("iter");
+
+ // `::std::option::Option::Some(<pat>) => <body>`
+ let pat_arm = {
+ let body_block = lower_block(lctx, body);
+ let body_span = body_block.span;
+ let body_expr = P(hir::Expr {
+ id: lctx.next_id(),
+ node: hir::ExprBlock(body_block),
+ span: body_span,
+ });
+ let pat = lower_pat(lctx, pat);
+ let some_pat = pat_some(lctx, e.span, pat);
+
+ arm(vec![some_pat], body_expr)
+ };
+
+ // `::std::option::Option::None => break`
+ let break_arm = {
+ let break_expr = expr_break(lctx, e.span);
+
+ arm(vec![pat_none(lctx, e.span)], break_expr)
+ };
+
+ // `match ::std::iter::Iterator::next(&mut iter) { ... }`
+ let match_expr = {
+ let next_path = {
+ let strs = std_path(lctx, &["iter", "Iterator", "next"]);
+
+ path_global(e.span, strs)
+ };
+ let ref_mut_iter = expr_mut_addr_of(lctx,
+ e.span,
+ expr_ident(lctx, e.span, iter));
+ let next_expr = expr_call(lctx,
+ e.span,
+ expr_path(lctx, next_path),
+ vec![ref_mut_iter]);
+ let arms = vec![pat_arm, break_arm];
+
+ expr(lctx,
+ e.span,
+ hir::ExprMatch(next_expr, arms, hir::MatchSource::ForLoopDesugar))
+ };
+
+ // `[opt_ident]: loop { ... }`
+ let loop_block = block_expr(lctx, match_expr);
+ let loop_expr = expr(lctx, e.span, hir::ExprLoop(loop_block, opt_ident));
+
+ // `mut iter => { ... }`
+ let iter_arm = {
+ let iter_pat = pat_ident_binding_mode(lctx,
+ e.span,
+ iter,
+ hir::BindByValue(hir::MutMutable));
+ arm(vec![iter_pat], loop_expr)
+ };
+
+ // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
+ let into_iter_expr = {
+ let into_iter_path = {
+ let strs = std_path(lctx, &["iter", "IntoIterator", "into_iter"]);
+
+ path_global(e.span, strs)
+ };
+
+ expr_call(lctx,
+ e.span,
+ expr_path(lctx, into_iter_path),
+ vec![head])
+ };
+
+ let match_expr = expr_match(lctx,
+ e.span,
+ into_iter_expr,
+ vec![iter_arm],
+ hir::MatchSource::ForLoopDesugar);
+
+ // `{ let result = ...; result }`
+ let result_ident = lctx.str_to_ident("result");
+ return expr_block(lctx,
+ block_all(lctx,
+ e.span,
+ vec![stmt_let(lctx,
+ e.span,
+ false,
+ result_ident,
+ match_expr)],
+ Some(expr_ident(lctx, e.span, result_ident))))
+ }
+
+ ExprMac(_) => panic!("Shouldn't exist here"),
+ },
+ span: e.span,
+ })
+}
+
+pub fn lower_stmt(_lctx: &LoweringContext, s: &Stmt) -> P<hir::Stmt> {
match s.node {
StmtDecl(ref d, id) => {
P(Spanned {
- node: hir::StmtDecl(lower_decl(d), id),
- span: s.span
+ node: hir::StmtDecl(lower_decl(_lctx, d), id),
+ span: s.span,
})
}
StmtExpr(ref e, id) => {
P(Spanned {
- node: hir::StmtExpr(lower_expr(e), id),
- span: s.span
+ node: hir::StmtExpr(lower_expr(_lctx, e), id),
+ span: s.span,
})
}
StmtSemi(ref e, id) => {
P(Spanned {
- node: hir::StmtSemi(lower_expr(e), id),
- span: s.span
+ node: hir::StmtSemi(lower_expr(_lctx, e), id),
+ span: s.span,
})
}
- StmtMac(..) => panic!("Shouldn't exist here")
- }
-}
-
-pub fn lower_string_style(s: StrStyle) -> hir::StrStyle {
- match s {
- CookedStr => hir::CookedStr,
- RawStr(u) => hir::RawStr(u),
- }
-}
-
-pub fn unlower_string_style(s: hir::StrStyle) -> StrStyle {
- match s {
- hir::CookedStr => CookedStr,
- hir::RawStr(u) => RawStr(u),
- }
-}
-
-pub fn lower_match_source(m: &MatchSource) -> hir::MatchSource {
- match *m {
- MatchSource::Normal => hir::MatchSource::Normal,
- MatchSource::IfLetDesugar { contains_else_clause } => {
- hir::MatchSource::IfLetDesugar { contains_else_clause: contains_else_clause }
- }
- MatchSource::WhileLetDesugar => hir::MatchSource::WhileLetDesugar,
- MatchSource::ForLoopDesugar => hir::MatchSource::ForLoopDesugar,
+ StmtMac(..) => panic!("Shouldn't exist here"),
}
}
-pub fn lower_capture_clause(c: CaptureClause) -> hir::CaptureClause {
+pub fn lower_capture_clause(_lctx: &LoweringContext, c: CaptureClause) -> hir::CaptureClause {
match c {
CaptureByValue => hir::CaptureByValue,
CaptureByRef => hir::CaptureByRef,
}
}
-pub fn lower_asm_dialect(a: AsmDialect) -> hir::AsmDialect {
- match a {
- AsmAtt => hir::AsmAtt,
- AsmIntel => hir::AsmIntel,
- }
-}
-
-pub fn lower_visibility(v: Visibility) -> hir::Visibility {
+pub fn lower_visibility(_lctx: &LoweringContext, v: Visibility) -> hir::Visibility {
match v {
Public => hir::Public,
Inherited => hir::Inherited,
}
}
-pub fn lower_block_check_mode(b: &BlockCheckMode) -> hir::BlockCheckMode {
+pub fn lower_block_check_mode(_lctx: &LoweringContext, b: &BlockCheckMode) -> hir::BlockCheckMode {
match *b {
DefaultBlock => hir::DefaultBlock,
- UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(u)),
- PushUnsafeBlock(u) => hir::PushUnsafeBlock(lower_unsafe_source(u)),
- PopUnsafeBlock(u) => hir::PopUnsafeBlock(lower_unsafe_source(u)),
+ UnsafeBlock(u) => hir::UnsafeBlock(lower_unsafe_source(_lctx, u)),
}
}
-pub fn lower_pat_wild_kind(p: PatWildKind) -> hir::PatWildKind {
+pub fn lower_pat_wild_kind(_lctx: &LoweringContext, p: PatWildKind) -> hir::PatWildKind {
match p {
PatWildSingle => hir::PatWildSingle,
PatWildMulti => hir::PatWildMulti,
}
}
-pub fn lower_binding_mode(b: &BindingMode) -> hir::BindingMode {
+pub fn lower_binding_mode(_lctx: &LoweringContext, b: &BindingMode) -> hir::BindingMode {
match *b {
- BindByRef(m) => hir::BindByRef(lower_mutability(m)),
- BindByValue(m) => hir::BindByValue(lower_mutability(m)),
+ BindByRef(m) => hir::BindByRef(lower_mutability(_lctx, m)),
+ BindByValue(m) => hir::BindByValue(lower_mutability(_lctx, m)),
}
}
-pub fn lower_struct_field_kind(s: &StructFieldKind) -> hir::StructFieldKind {
+pub fn lower_struct_field_kind(_lctx: &LoweringContext,
+ s: &StructFieldKind)
+ -> hir::StructFieldKind {
match *s {
- NamedField(ident, vis) => hir::NamedField(ident, lower_visibility(vis)),
- UnnamedField(vis) => hir::UnnamedField(lower_visibility(vis)),
+ NamedField(ident, vis) => hir::NamedField(ident.name, lower_visibility(_lctx, vis)),
+ UnnamedField(vis) => hir::UnnamedField(lower_visibility(_lctx, vis)),
}
}
-pub fn lower_unsafe_source(u: UnsafeSource) -> hir::UnsafeSource {
+pub fn lower_unsafe_source(_lctx: &LoweringContext, u: UnsafeSource) -> hir::UnsafeSource {
match u {
CompilerGenerated => hir::CompilerGenerated,
UserProvided => hir::UserProvided,
}
}
-pub fn lower_impl_polarity(i: ImplPolarity) -> hir::ImplPolarity {
+pub fn lower_impl_polarity(_lctx: &LoweringContext, i: ImplPolarity) -> hir::ImplPolarity {
match i {
ImplPolarity::Positive => hir::ImplPolarity::Positive,
ImplPolarity::Negative => hir::ImplPolarity::Negative,
}
}
-pub fn lower_float_ty(f: FloatTy) -> hir::FloatTy {
+pub fn lower_trait_bound_modifier(_lctx: &LoweringContext,
+ f: TraitBoundModifier)
+ -> hir::TraitBoundModifier {
match f {
- TyF32 => hir::TyF32,
- TyF64 => hir::TyF64,
+ TraitBoundModifier::None => hir::TraitBoundModifier::None,
+ TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
}
}
-pub fn unlower_float_ty(f: hir::FloatTy) -> FloatTy {
- match f {
- hir::TyF32 => TyF32,
- hir::TyF64 => TyF64,
+// Helper methods for building HIR.
+
+fn arm(pats: Vec<P<hir::Pat>>, expr: P<hir::Expr>) -> hir::Arm {
+ hir::Arm {
+ attrs: vec!(),
+ pats: pats,
+ guard: None,
+ body: expr,
}
}
-pub fn lower_lit_int_type(i: &LitIntType) -> hir::LitIntType {
- match *i {
- SignedIntLit(i, s) => hir::SignedIntLit(lower_int_ty(i), lower_sign(s)),
- UnsignedIntLit(u) => hir::UnsignedIntLit(lower_uint_ty(u)),
- UnsuffixedIntLit(s) => hir::UnsuffixedIntLit(lower_sign(s)),
- }
+fn expr_break(lctx: &LoweringContext, span: Span) -> P<hir::Expr> {
+ expr(lctx, span, hir::ExprBreak(None))
}
-pub fn unlower_lit_int_type(i: &hir::LitIntType) -> LitIntType {
- match *i {
- hir::SignedIntLit(i, s) => SignedIntLit(unlower_int_ty(i), unlower_sign(s)),
- hir::UnsignedIntLit(u) => UnsignedIntLit(unlower_uint_ty(u)),
- hir::UnsuffixedIntLit(s) => UnsuffixedIntLit(unlower_sign(s)),
- }
+fn expr_call(lctx: &LoweringContext,
+ span: Span,
+ e: P<hir::Expr>,
+ args: Vec<P<hir::Expr>>)
+ -> P<hir::Expr> {
+ expr(lctx, span, hir::ExprCall(e, args))
}
-pub fn lower_int_ty(i: IntTy) -> hir::IntTy {
- match i {
- TyIs => hir::TyIs,
- TyI8 => hir::TyI8,
- TyI16 => hir::TyI16,
- TyI32 => hir::TyI32,
- TyI64 => hir::TyI64,
- }
+fn expr_ident(lctx: &LoweringContext, span: Span, id: Ident) -> P<hir::Expr> {
+ expr_path(lctx, path_ident(span, id))
}
-pub fn unlower_int_ty(i: hir::IntTy) -> IntTy {
- match i {
- hir::TyIs => TyIs,
- hir::TyI8 => TyI8,
- hir::TyI16 => TyI16,
- hir::TyI32 => TyI32,
- hir::TyI64 => TyI64,
- }
+fn expr_mut_addr_of(lctx: &LoweringContext, span: Span, e: P<hir::Expr>) -> P<hir::Expr> {
+ expr(lctx, span, hir::ExprAddrOf(hir::MutMutable, e))
}
-pub fn lower_uint_ty(u: UintTy) -> hir::UintTy {
- match u {
- TyUs => hir::TyUs,
- TyU8 => hir::TyU8,
- TyU16 => hir::TyU16,
- TyU32 => hir::TyU32,
- TyU64 => hir::TyU64,
- }
+fn expr_path(lctx: &LoweringContext, path: hir::Path) -> P<hir::Expr> {
+ expr(lctx, path.span, hir::ExprPath(None, path))
}
-pub fn unlower_uint_ty(u: hir::UintTy) -> UintTy {
- match u {
- hir::TyUs => TyUs,
- hir::TyU8 => TyU8,
- hir::TyU16 => TyU16,
- hir::TyU32 => TyU32,
- hir::TyU64 => TyU64,
- }
+fn expr_match(lctx: &LoweringContext,
+ span: Span,
+ arg: P<hir::Expr>,
+ arms: Vec<hir::Arm>,
+ source: hir::MatchSource)
+ -> P<hir::Expr> {
+ expr(lctx,
+ span,
+ hir::ExprMatch(arg, arms, source))
}
-pub fn lower_sign(f: Sign) -> hir::Sign {
- match f {
- Minus => hir::Minus,
- Plus => hir::Plus,
- }
+fn expr_block(lctx: &LoweringContext, b: P<hir::Block>) -> P<hir::Expr> {
+ expr(lctx, b.span, hir::ExprBlock(b))
}
-pub fn unlower_sign(f: hir::Sign) -> Sign {
- match f {
- hir::Minus => Minus,
- hir::Plus => Plus,
- }
+fn expr_tuple(lctx: &LoweringContext, sp: Span, exprs: Vec<P<hir::Expr>>) -> P<hir::Expr> {
+ expr(lctx, sp, hir::ExprTup(exprs))
}
-pub fn lower_trait_bound_modifier(f: TraitBoundModifier) -> hir::TraitBoundModifier {
- match f {
- TraitBoundModifier::None => hir::TraitBoundModifier::None,
- TraitBoundModifier::Maybe => hir::TraitBoundModifier::Maybe,
+fn expr(lctx: &LoweringContext, span: Span, node: hir::Expr_) -> P<hir::Expr> {
+ P(hir::Expr {
+ id: lctx.next_id(),
+ node: node,
+ span: span,
+ })
+}
+
+fn stmt_let(lctx: &LoweringContext,
+ sp: Span,
+ mutbl: bool,
+ ident: Ident,
+ ex: P<hir::Expr>)
+ -> P<hir::Stmt> {
+ let pat = if mutbl {
+ pat_ident_binding_mode(lctx, sp, ident, hir::BindByValue(hir::MutMutable))
+ } else {
+ pat_ident(lctx, sp, ident)
+ };
+ let local = P(hir::Local {
+ pat: pat,
+ ty: None,
+ init: Some(ex),
+ id: lctx.next_id(),
+ span: sp,
+ });
+ let decl = respan(sp, hir::DeclLocal(local));
+ P(respan(sp, hir::StmtDecl(P(decl), lctx.next_id())))
+}
+
+fn block_expr(lctx: &LoweringContext, expr: P<hir::Expr>) -> P<hir::Block> {
+ block_all(lctx, expr.span, Vec::new(), Some(expr))
+}
+
+fn block_all(lctx: &LoweringContext,
+ span: Span,
+ stmts: Vec<P<hir::Stmt>>,
+ expr: Option<P<hir::Expr>>)
+ -> P<hir::Block> {
+ P(hir::Block {
+ stmts: stmts,
+ expr: expr,
+ id: lctx.next_id(),
+ rules: hir::DefaultBlock,
+ span: span,
+ })
+}
+
+fn pat_some(lctx: &LoweringContext, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
+ let some = std_path(lctx, &["option", "Option", "Some"]);
+ let path = path_global(span, some);
+ pat_enum(lctx, span, path, vec!(pat))
+}
+
+fn pat_none(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
+ let none = std_path(lctx, &["option", "Option", "None"]);
+ let path = path_global(span, none);
+ pat_enum(lctx, span, path, vec![])
+}
+
+fn pat_enum(lctx: &LoweringContext,
+ span: Span,
+ path: hir::Path,
+ subpats: Vec<P<hir::Pat>>)
+ -> P<hir::Pat> {
+ let pt = hir::PatEnum(path, Some(subpats));
+ pat(lctx, span, pt)
+}
+
+fn pat_ident(lctx: &LoweringContext, span: Span, ident: Ident) -> P<hir::Pat> {
+ pat_ident_binding_mode(lctx, span, ident, hir::BindByValue(hir::MutImmutable))
+}
+
+fn pat_ident_binding_mode(lctx: &LoweringContext,
+ span: Span,
+ ident: Ident,
+ bm: hir::BindingMode)
+ -> P<hir::Pat> {
+ let pat_ident = hir::PatIdent(bm,
+ Spanned {
+ span: span,
+ node: ident,
+ },
+ None);
+ pat(lctx, span, pat_ident)
+}
+
+fn pat_wild(lctx: &LoweringContext, span: Span) -> P<hir::Pat> {
+ pat(lctx, span, hir::PatWild(hir::PatWildSingle))
+}
+
+fn pat(lctx: &LoweringContext, span: Span, pat: hir::Pat_) -> P<hir::Pat> {
+ P(hir::Pat {
+ id: lctx.next_id(),
+ node: pat,
+ span: span,
+ })
+}
+
+fn path_ident(span: Span, id: Ident) -> hir::Path {
+ path(span, vec!(id))
+}
+
+fn path(span: Span, strs: Vec<Ident>) -> hir::Path {
+ path_all(span, false, strs, Vec::new(), Vec::new(), Vec::new())
+}
+
+fn path_global(span: Span, strs: Vec<Ident>) -> hir::Path {
+ path_all(span, true, strs, Vec::new(), Vec::new(), Vec::new())
+}
+
+fn path_all(sp: Span,
+ global: bool,
+ mut idents: Vec<Ident>,
+ lifetimes: Vec<hir::Lifetime>,
+ types: Vec<P<hir::Ty>>,
+ bindings: Vec<P<hir::TypeBinding>>)
+ -> hir::Path {
+ let last_identifier = idents.pop().unwrap();
+ let mut segments: Vec<hir::PathSegment> = idents.into_iter()
+ .map(|ident| {
+ hir::PathSegment {
+ identifier: ident,
+ parameters: hir::PathParameters::none(),
+ }
+ })
+ .collect();
+ segments.push(hir::PathSegment {
+ identifier: last_identifier,
+ parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
+ lifetimes: lifetimes,
+ types: OwnedSlice::from_vec(types),
+ bindings: OwnedSlice::from_vec(bindings),
+ }),
+ });
+ hir::Path {
+ span: sp,
+ global: global,
+ segments: segments,
}
}
-pub fn lower_attr_style(f: AttrStyle) -> hir::AttrStyle {
- match f {
- AttrOuter => hir::AttrOuter,
- AttrInner => hir::AttrInner,
+fn std_path(lctx: &LoweringContext, components: &[&str]) -> Vec<Ident> {
+ let mut v = Vec::new();
+ if let Some(s) = lctx.crate_root {
+ v.push(str_to_ident(s));
}
+ v.extend(components.iter().map(|s| str_to_ident(s)));
+ return v
}
-pub fn unlower_attr_style(f: hir::AttrStyle) -> AttrStyle {
- match f {
- hir::AttrOuter => AttrOuter,
- hir::AttrInner => AttrInner,
+// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
+// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
+fn core_path(lctx: &LoweringContext, span: Span, components: &[&str]) -> hir::Path {
+ let idents = std_path(lctx, components);
+ path_global(span, idents)
+}
+
+fn signal_block_expr(lctx: &LoweringContext,
+ stmts: Vec<P<hir::Stmt>>,
+ expr: P<hir::Expr>,
+ span: Span,
+ rule: hir::BlockCheckMode)
+ -> P<hir::Expr> {
+ expr_block(lctx,
+ P(hir::Block {
+ rules: rule,
+ span: span,
+ id: lctx.next_id(),
+ stmts: stmts,
+ expr: Some(expr),
+ }))
+}
+
+
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use syntax::ast::{self, NodeId, NodeIdAssigner};
+ use syntax::{parse, codemap};
+ use syntax::fold::Folder;
+ use std::cell::Cell;
+
+ struct MockAssigner {
+ next_id: Cell<NodeId>,
+ }
+
+ impl MockAssigner {
+ fn new() -> MockAssigner {
+ MockAssigner {
+ next_id: Cell::new(0),
+ }
+ }
+ }
+
+ trait FakeExtCtxt {
+ fn call_site(&self) -> codemap::Span;
+ fn cfg(&self) -> ast::CrateConfig;
+ fn ident_of(&self, st: &str) -> ast::Ident;
+ fn name_of(&self, st: &str) -> ast::Name;
+ fn parse_sess(&self) -> &parse::ParseSess;
+ }
+
+ impl FakeExtCtxt for parse::ParseSess {
+ fn call_site(&self) -> codemap::Span {
+ codemap::Span {
+ lo: codemap::BytePos(0),
+ hi: codemap::BytePos(0),
+ expn_id: codemap::NO_EXPANSION,
+ }
+ }
+ fn cfg(&self) -> ast::CrateConfig { Vec::new() }
+ fn ident_of(&self, st: &str) -> ast::Ident {
+ parse::token::str_to_ident(st)
+ }
+ fn name_of(&self, st: &str) -> ast::Name {
+ parse::token::intern(st)
+ }
+ fn parse_sess(&self) -> &parse::ParseSess { self }
+ }
+
+ impl NodeIdAssigner for MockAssigner {
+ fn next_node_id(&self) -> NodeId {
+ let result = self.next_id.get();
+ self.next_id.set(result + 1);
+ result
+ }
+
+ fn peek_node_id(&self) -> NodeId {
+ self.next_id.get()
+ }
+ }
+
+ impl Folder for MockAssigner {
+ fn new_id(&mut self, old_id: NodeId) -> NodeId {
+ assert_eq!(old_id, ast::DUMMY_NODE_ID);
+ self.next_node_id()
+ }
+ }
+
+ #[test]
+ fn test_preserves_ids() {
+ let cx = parse::ParseSess::new();
+ let mut assigner = MockAssigner::new();
+
+ let ast_if_let = quote_expr!(&cx, if let Some(foo) = baz { bar(foo); });
+ let ast_if_let = assigner.fold_expr(ast_if_let);
+ let ast_while_let = quote_expr!(&cx, while let Some(foo) = baz { bar(foo); });
+ let ast_while_let = assigner.fold_expr(ast_while_let);
+ let ast_for = quote_expr!(&cx, for i in 0..10 { foo(i); });
+ let ast_for = assigner.fold_expr(ast_for);
+ let ast_in = quote_expr!(&cx, in HEAP { foo() });
+ let ast_in = assigner.fold_expr(ast_in);
+
+ let lctx = LoweringContext::new(&assigner, None);
+ let hir1 = lower_expr(&lctx, &ast_if_let);
+ let hir2 = lower_expr(&lctx, &ast_if_let);
+ assert!(hir1 == hir2);
+
+ let hir1 = lower_expr(&lctx, &ast_while_let);
+ let hir2 = lower_expr(&lctx, &ast_while_let);
+ assert!(hir1 == hir2);
+
+ let hir1 = lower_expr(&lctx, &ast_for);
+ let hir2 = lower_expr(&lctx, &ast_for);
+ assert!(hir1 == hir2);
+
+ let hir1 = lower_expr(&lctx, &ast_in);
+ let hir2 = lower_expr(&lctx, &ast_in);
+ assert!(hir1 == hir2);
}
}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! This pretty-printer is a direct reimplementation of Philip Karlton's
-//! Mesa pretty-printer, as described in appendix A of
-//!
-//! STAN-CS-79-770: "Pretty Printing", by Derek C. Oppen.
-//! Stanford Department of Computer Science, 1979.
-//!
-//! The algorithm's aim is to break a stream into as few lines as possible
-//! while respecting the indentation-consistency requirements of the enclosing
-//! block, and avoiding breaking at silly places on block boundaries, for
-//! example, between "x" and ")" in "x)".
-//!
-//! I am implementing this algorithm because it comes with 20 pages of
-//! documentation explaining its theory, and because it addresses the set of
-//! concerns I've seen other pretty-printers fall down on. Weirdly. Even though
-//! it's 32 years old. What can I say?
-//!
-//! Despite some redundancies and quirks in the way it's implemented in that
-//! paper, I've opted to keep the implementation here as similar as I can,
-//! changing only what was blatantly wrong, a typo, or sufficiently
-//! non-idiomatic rust that it really stuck out.
-//!
-//! In particular you'll see a certain amount of churn related to INTEGER vs.
-//! CARDINAL in the Mesa implementation. Mesa apparently interconverts the two
-//! somewhat readily? In any case, I've used usize for indices-in-buffers and
-//! ints for character-sizes-and-indentation-offsets. This respects the need
-//! for ints to "go negative" while carrying a pending-calculation balance, and
-//! helps differentiate all the numbers flying around internally (slightly).
-//!
-//! I also inverted the indentation arithmetic used in the print stack, since
-//! the Mesa implementation (somewhat randomly) stores the offset on the print
-//! stack in terms of margin-col rather than col itself. I store col.
-//!
-//! I also implemented a small change in the String token, in that I store an
-//! explicit length for the string. For most tokens this is just the length of
-//! the accompanying string. But it's necessary to permit it to differ, for
-//! encoding things that are supposed to "go on their own line" -- certain
-//! classes of comment and blank-line -- where relying on adjacent
-//! hardbreak-like Break tokens with long blankness indication doesn't actually
-//! work. To see why, consider when there is a "thing that should be on its own
-//! line" between two long blocks, say functions. If you put a hardbreak after
-//! each function (or before each) and the breaking algorithm decides to break
-//! there anyways (because the functions themselves are long) you wind up with
-//! extra blank lines. If you don't put hardbreaks you can wind up with the
-//! "thing which should be on its own line" not getting its own line in the
-//! rare case of "really small functions" or such. This re-occurs with comments
-//! and explicit blank lines. So in those cases we use a string with a payload
-//! we want isolated to a line and an explicit length that's huge, surrounded
-//! by two zero-length breaks. The algorithm will try its best to fit it on a
-//! line (which it can't) and so naturally place the content on its own line to
-//! avoid combining it with other lines and making matters even worse.
-
-use std::io;
-use std::string;
-
-#[derive(Clone, Copy, PartialEq)]
-pub enum Breaks {
- Consistent,
- Inconsistent,
-}
-
-#[derive(Clone, Copy)]
-pub struct BreakToken {
- offset: isize,
- blank_space: isize
-}
-
-#[derive(Clone, Copy)]
-pub struct BeginToken {
- offset: isize,
- breaks: Breaks
-}
-
-#[derive(Clone)]
-pub enum Token {
- String(String, isize),
- Break(BreakToken),
- Begin(BeginToken),
- End,
- Eof,
-}
-
-impl Token {
- pub fn is_eof(&self) -> bool {
- match *self {
- Token::Eof => true,
- _ => false,
- }
- }
-
- pub fn is_hardbreak_tok(&self) -> bool {
- match *self {
- Token::Break(BreakToken {
- offset: 0,
- blank_space: bs
- }) if bs == SIZE_INFINITY =>
- true,
- _ =>
- false
- }
- }
-}
-
-pub fn tok_str(token: &Token) -> String {
- match *token {
- Token::String(ref s, len) => format!("STR({},{})", s, len),
- Token::Break(_) => "BREAK".to_string(),
- Token::Begin(_) => "BEGIN".to_string(),
- Token::End => "END".to_string(),
- Token::Eof => "EOF".to_string()
- }
-}
-
-pub fn buf_str(toks: &[Token],
- szs: &[isize],
- left: usize,
- right: usize,
- lim: usize)
- -> String {
- let n = toks.len();
- assert_eq!(n, szs.len());
- let mut i = left;
- let mut l = lim;
- let mut s = string::String::from("[");
- while i != right && l != 0 {
- l -= 1;
- if i != left {
- s.push_str(", ");
- }
- s.push_str(&format!("{}={}",
- szs[i],
- tok_str(&toks[i])));
- i += 1;
- i %= n;
- }
- s.push(']');
- s
-}
-
-#[derive(Copy, Clone)]
-pub enum PrintStackBreak {
- Fits,
- Broken(Breaks),
-}
-
-#[derive(Copy, Clone)]
-pub struct PrintStackElem {
- offset: isize,
- pbreak: PrintStackBreak
-}
-
-const SIZE_INFINITY: isize = 0xffff;
-
-pub fn mk_printer<'a>(out: Box<io::Write+'a>, linewidth: usize) -> Printer<'a> {
- // Yes 3, it makes the ring buffers big enough to never
- // fall behind.
- let n: usize = 3 * linewidth;
- debug!("mk_printer {}", linewidth);
- let token = vec![Token::Eof; n];
- let size = vec![0_isize; n];
- let scan_stack = vec![0_usize; n];
- Printer {
- out: out,
- buf_len: n,
- margin: linewidth as isize,
- space: linewidth as isize,
- left: 0,
- right: 0,
- token: token,
- size: size,
- left_total: 0,
- right_total: 0,
- scan_stack: scan_stack,
- scan_stack_empty: true,
- top: 0,
- bottom: 0,
- print_stack: Vec::new(),
- pending_indentation: 0
- }
-}
-
-
-/// In case you do not have the paper, here is an explanation of what's going
-/// on.
-///
-/// There is a stream of input tokens flowing through this printer.
-///
-/// The printer buffers up to 3N tokens inside itself, where N is linewidth.
-/// Yes, linewidth is chars and tokens are multi-char, but in the worst
-/// case every token worth buffering is 1 char long, so it's ok.
-///
-/// Tokens are String, Break, and Begin/End to delimit blocks.
-///
-/// Begin tokens can carry an offset, saying "how far to indent when you break
-/// inside here", as well as a flag indicating "consistent" or "inconsistent"
-/// breaking. Consistent breaking means that after the first break, no attempt
-/// will be made to flow subsequent breaks together onto lines. Inconsistent
-/// is the opposite. Inconsistent breaking example would be, say:
-///
-/// foo(hello, there, good, friends)
-///
-/// breaking inconsistently to become
-///
-/// foo(hello, there
-/// good, friends);
-///
-/// whereas a consistent breaking would yield:
-///
-/// foo(hello,
-/// there
-/// good,
-/// friends);
-///
-/// That is, in the consistent-break blocks we value vertical alignment
-/// more than the ability to cram stuff onto a line. But in all cases if it
-/// can make a block a one-liner, it'll do so.
-///
-/// Carrying on with high-level logic:
-///
-/// The buffered tokens go through a ring-buffer, 'tokens'. The 'left' and
-/// 'right' indices denote the active portion of the ring buffer as well as
-/// describing hypothetical points-in-the-infinite-stream at most 3N tokens
-/// apart (i.e. "not wrapped to ring-buffer boundaries"). The paper will switch
-/// between using 'left' and 'right' terms to denote the wrapped-to-ring-buffer
-/// and point-in-infinite-stream senses freely.
-///
-/// There is a parallel ring buffer, 'size', that holds the calculated size of
-/// each token. Why calculated? Because for Begin/End pairs, the "size"
-/// includes everything between the pair. That is, the "size" of Begin is
-/// actually the sum of the sizes of everything between Begin and the paired
-/// End that follows. Since that is arbitrarily far in the future, 'size' is
-/// being rewritten regularly while the printer runs; in fact most of the
-/// machinery is here to work out 'size' entries on the fly (and give up when
-/// they're so obviously over-long that "infinity" is a good enough
-/// approximation for purposes of line breaking).
-///
-/// The "input side" of the printer is managed as an abstract process called
-/// SCAN, which uses 'scan_stack', 'scan_stack_empty', 'top' and 'bottom', to
-/// manage calculating 'size'. SCAN is, in other words, the process of
-/// calculating 'size' entries.
-///
-/// The "output side" of the printer is managed by an abstract process called
-/// PRINT, which uses 'print_stack', 'margin' and 'space' to figure out what to
-/// do with each token/size pair it consumes as it goes. It's trying to consume
-/// the entire buffered window, but can't output anything until the size is >=
-/// 0 (sizes are set to negative while they're pending calculation).
-///
-/// So SCAN takes input and buffers tokens and pending calculations, while
-/// PRINT gobbles up completed calculations and tokens from the buffer. The
-/// theory is that the two can never get more than 3N tokens apart, because
-/// once there's "obviously" too much data to fit on a line, in a size
-/// calculation, SCAN will write "infinity" to the size and let PRINT consume
-/// it.
-///
-/// In this implementation (following the paper, again) the SCAN process is
-/// the method called 'pretty_print', and the 'PRINT' process is the method
-/// called 'print'.
-pub struct Printer<'a> {
- pub out: Box<io::Write+'a>,
- buf_len: usize,
- /// Width of lines we're constrained to
- margin: isize,
- /// Number of spaces left on line
- space: isize,
- /// Index of left side of input stream
- left: usize,
- /// Index of right side of input stream
- right: usize,
- /// Ring-buffer stream goes through
- token: Vec<Token> ,
- /// Ring-buffer of calculated sizes
- size: Vec<isize> ,
- /// Running size of stream "...left"
- left_total: isize,
- /// Running size of stream "...right"
- right_total: isize,
- /// Pseudo-stack, really a ring too. Holds the
- /// primary-ring-buffers index of the Begin that started the
- /// current block, possibly with the most recent Break after that
- /// Begin (if there is any) on top of it. Stuff is flushed off the
- /// bottom as it becomes irrelevant due to the primary ring-buffer
- /// advancing.
- scan_stack: Vec<usize> ,
- /// Top==bottom disambiguator
- scan_stack_empty: bool,
- /// Index of top of scan_stack
- top: usize,
- /// Index of bottom of scan_stack
- bottom: usize,
- /// Stack of blocks-in-progress being flushed by print
- print_stack: Vec<PrintStackElem> ,
- /// Buffered indentation to avoid writing trailing whitespace
- pending_indentation: isize,
-}
-
-impl<'a> Printer<'a> {
- pub fn last_token(&mut self) -> Token {
- self.token[self.right].clone()
- }
- // be very careful with this!
- pub fn replace_last_token(&mut self, t: Token) {
- self.token[self.right] = t;
- }
- pub fn pretty_print(&mut self, token: Token) -> io::Result<()> {
- debug!("pp Vec<{},{}>", self.left, self.right);
- match token {
- Token::Eof => {
- if !self.scan_stack_empty {
- self.check_stack(0);
- try!(self.advance_left());
- }
- self.indent(0);
- Ok(())
- }
- Token::Begin(b) => {
- if self.scan_stack_empty {
- self.left_total = 1;
- self.right_total = 1;
- self.left = 0;
- self.right = 0;
- } else { self.advance_right(); }
- debug!("pp Begin({})/buffer Vec<{},{}>",
- b.offset, self.left, self.right);
- self.token[self.right] = token;
- self.size[self.right] = -self.right_total;
- let right = self.right;
- self.scan_push(right);
- Ok(())
- }
- Token::End => {
- if self.scan_stack_empty {
- debug!("pp End/print Vec<{},{}>", self.left, self.right);
- self.print(token, 0)
- } else {
- debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
- self.advance_right();
- self.token[self.right] = token;
- self.size[self.right] = -1;
- let right = self.right;
- self.scan_push(right);
- Ok(())
- }
- }
- Token::Break(b) => {
- if self.scan_stack_empty {
- self.left_total = 1;
- self.right_total = 1;
- self.left = 0;
- self.right = 0;
- } else { self.advance_right(); }
- debug!("pp Break({})/buffer Vec<{},{}>",
- b.offset, self.left, self.right);
- self.check_stack(0);
- let right = self.right;
- self.scan_push(right);
- self.token[self.right] = token;
- self.size[self.right] = -self.right_total;
- self.right_total += b.blank_space;
- Ok(())
- }
- Token::String(s, len) => {
- if self.scan_stack_empty {
- debug!("pp String('{}')/print Vec<{},{}>",
- s, self.left, self.right);
- self.print(Token::String(s, len), len)
- } else {
- debug!("pp String('{}')/buffer Vec<{},{}>",
- s, self.left, self.right);
- self.advance_right();
- self.token[self.right] = Token::String(s, len);
- self.size[self.right] = len;
- self.right_total += len;
- self.check_stream()
- }
- }
- }
- }
- pub fn check_stream(&mut self) -> io::Result<()> {
- debug!("check_stream Vec<{}, {}> with left_total={}, right_total={}",
- self.left, self.right, self.left_total, self.right_total);
- if self.right_total - self.left_total > self.space {
- debug!("scan window is {}, longer than space on line ({})",
- self.right_total - self.left_total, self.space);
- if !self.scan_stack_empty {
- if self.left == self.scan_stack[self.bottom] {
- debug!("setting {} to infinity and popping", self.left);
- let scanned = self.scan_pop_bottom();
- self.size[scanned] = SIZE_INFINITY;
- }
- }
- try!(self.advance_left());
- if self.left != self.right {
- try!(self.check_stream());
- }
- }
- Ok(())
- }
- pub fn scan_push(&mut self, x: usize) {
- debug!("scan_push {}", x);
- if self.scan_stack_empty {
- self.scan_stack_empty = false;
- } else {
- self.top += 1;
- self.top %= self.buf_len;
- assert!((self.top != self.bottom));
- }
- self.scan_stack[self.top] = x;
- }
- pub fn scan_pop(&mut self) -> usize {
- assert!((!self.scan_stack_empty));
- let x = self.scan_stack[self.top];
- if self.top == self.bottom {
- self.scan_stack_empty = true;
- } else {
- self.top += self.buf_len - 1; self.top %= self.buf_len;
- }
- return x;
- }
- pub fn scan_top(&mut self) -> usize {
- assert!((!self.scan_stack_empty));
- return self.scan_stack[self.top];
- }
- pub fn scan_pop_bottom(&mut self) -> usize {
- assert!((!self.scan_stack_empty));
- let x = self.scan_stack[self.bottom];
- if self.top == self.bottom {
- self.scan_stack_empty = true;
- } else {
- self.bottom += 1; self.bottom %= self.buf_len;
- }
- return x;
- }
- pub fn advance_right(&mut self) {
- self.right += 1;
- self.right %= self.buf_len;
- assert!((self.right != self.left));
- }
- pub fn advance_left(&mut self) -> io::Result<()> {
- debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right,
- self.left, self.size[self.left]);
-
- let mut left_size = self.size[self.left];
-
- while left_size >= 0 {
- let left = self.token[self.left].clone();
-
- let len = match left {
- Token::Break(b) => b.blank_space,
- Token::String(_, len) => {
- assert_eq!(len, left_size);
- len
- }
- _ => 0
- };
-
- try!(self.print(left, left_size));
-
- self.left_total += len;
-
- if self.left == self.right {
- break;
- }
-
- self.left += 1;
- self.left %= self.buf_len;
-
- left_size = self.size[self.left];
- }
-
- Ok(())
- }
- pub fn check_stack(&mut self, k: isize) {
- if !self.scan_stack_empty {
- let x = self.scan_top();
- match self.token[x] {
- Token::Begin(_) => {
- if k > 0 {
- let popped = self.scan_pop();
- self.size[popped] = self.size[x] + self.right_total;
- self.check_stack(k - 1);
- }
- }
- Token::End => {
- // paper says + not =, but that makes no sense.
- let popped = self.scan_pop();
- self.size[popped] = 1;
- self.check_stack(k + 1);
- }
- _ => {
- let popped = self.scan_pop();
- self.size[popped] = self.size[x] + self.right_total;
- if k > 0 {
- self.check_stack(k);
- }
- }
- }
- }
- }
- pub fn print_newline(&mut self, amount: isize) -> io::Result<()> {
- debug!("NEWLINE {}", amount);
- let ret = write!(self.out, "\n");
- self.pending_indentation = 0;
- self.indent(amount);
- return ret;
- }
- pub fn indent(&mut self, amount: isize) {
- debug!("INDENT {}", amount);
- self.pending_indentation += amount;
- }
- pub fn get_top(&mut self) -> PrintStackElem {
- let print_stack = &mut self.print_stack;
- let n = print_stack.len();
- if n != 0 {
- (*print_stack)[n - 1]
- } else {
- PrintStackElem {
- offset: 0,
- pbreak: PrintStackBreak::Broken(Breaks::Inconsistent)
- }
- }
- }
- pub fn print_str(&mut self, s: &str) -> io::Result<()> {
- while self.pending_indentation > 0 {
- try!(write!(self.out, " "));
- self.pending_indentation -= 1;
- }
- write!(self.out, "{}", s)
- }
- pub fn print(&mut self, token: Token, l: isize) -> io::Result<()> {
- debug!("print {} {} (remaining line space={})", tok_str(&token), l,
- self.space);
- debug!("{}", buf_str(&self.token,
- &self.size,
- self.left,
- self.right,
- 6));
- match token {
- Token::Begin(b) => {
- if l > self.space {
- let col = self.margin - self.space + b.offset;
- debug!("print Begin -> push broken block at col {}", col);
- self.print_stack.push(PrintStackElem {
- offset: col,
- pbreak: PrintStackBreak::Broken(b.breaks)
- });
- } else {
- debug!("print Begin -> push fitting block");
- self.print_stack.push(PrintStackElem {
- offset: 0,
- pbreak: PrintStackBreak::Fits
- });
- }
- Ok(())
- }
- Token::End => {
- debug!("print End -> pop End");
- let print_stack = &mut self.print_stack;
- assert!((!print_stack.is_empty()));
- print_stack.pop().unwrap();
- Ok(())
- }
- Token::Break(b) => {
- let top = self.get_top();
- match top.pbreak {
- PrintStackBreak::Fits => {
- debug!("print Break({}) in fitting block", b.blank_space);
- self.space -= b.blank_space;
- self.indent(b.blank_space);
- Ok(())
- }
- PrintStackBreak::Broken(Breaks::Consistent) => {
- debug!("print Break({}+{}) in consistent block",
- top.offset, b.offset);
- let ret = self.print_newline(top.offset + b.offset);
- self.space = self.margin - (top.offset + b.offset);
- ret
- }
- PrintStackBreak::Broken(Breaks::Inconsistent) => {
- if l > self.space {
- debug!("print Break({}+{}) w/ newline in inconsistent",
- top.offset, b.offset);
- let ret = self.print_newline(top.offset + b.offset);
- self.space = self.margin - (top.offset + b.offset);
- ret
- } else {
- debug!("print Break({}) w/o newline in inconsistent",
- b.blank_space);
- self.indent(b.blank_space);
- self.space -= b.blank_space;
- Ok(())
- }
- }
- }
- }
- Token::String(s, len) => {
- debug!("print String({})", s);
- assert_eq!(l, len);
- // assert!(l <= space);
- self.space -= len;
- self.print_str(&s[..])
- }
- Token::Eof => {
- // Eof should never get here.
- panic!();
- }
- }
- }
-}
-
-// Convenience functions to talk to the printer.
-//
-// "raw box"
-pub fn rbox(p: &mut Printer, indent: usize, b: Breaks) -> io::Result<()> {
- p.pretty_print(Token::Begin(BeginToken {
- offset: indent as isize,
- breaks: b
- }))
-}
-
-pub fn ibox(p: &mut Printer, indent: usize) -> io::Result<()> {
- rbox(p, indent, Breaks::Inconsistent)
-}
-
-pub fn cbox(p: &mut Printer, indent: usize) -> io::Result<()> {
- rbox(p, indent, Breaks::Consistent)
-}
-
-pub fn break_offset(p: &mut Printer, n: usize, off: isize) -> io::Result<()> {
- p.pretty_print(Token::Break(BreakToken {
- offset: off,
- blank_space: n as isize
- }))
-}
-
-pub fn end(p: &mut Printer) -> io::Result<()> {
- p.pretty_print(Token::End)
-}
-
-pub fn eof(p: &mut Printer) -> io::Result<()> {
- p.pretty_print(Token::Eof)
-}
-
-pub fn word(p: &mut Printer, wrd: &str) -> io::Result<()> {
- p.pretty_print(Token::String(/* bad */ wrd.to_string(), wrd.len() as isize))
-}
-
-pub fn huge_word(p: &mut Printer, wrd: &str) -> io::Result<()> {
- p.pretty_print(Token::String(/* bad */ wrd.to_string(), SIZE_INFINITY))
-}
-
-pub fn zero_word(p: &mut Printer, wrd: &str) -> io::Result<()> {
- p.pretty_print(Token::String(/* bad */ wrd.to_string(), 0))
-}
-
-pub fn spaces(p: &mut Printer, n: usize) -> io::Result<()> {
- break_offset(p, n, 0)
-}
-
-pub fn zerobreak(p: &mut Printer) -> io::Result<()> {
- spaces(p, 0)
-}
-
-pub fn space(p: &mut Printer) -> io::Result<()> {
- spaces(p, 1)
-}
-
-pub fn hardbreak(p: &mut Printer) -> io::Result<()> {
- spaces(p, SIZE_INFINITY as usize)
-}
-
-pub fn hardbreak_tok_offset(off: isize) -> Token {
- Token::Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
-}
-
-pub fn hardbreak_tok() -> Token {
- hardbreak_tok_offset(0)
-}
use syntax::abi;
use syntax::ast;
use syntax::owned_slice::OwnedSlice;
-use syntax::codemap::{self, CodeMap, BytePos};
+use syntax::codemap::{self, CodeMap, BytePos, Spanned};
use syntax::diagnostic;
use syntax::parse::token::{self, BinOpToken};
use syntax::parse::lexer::comments;
use syntax::parse;
-use syntax::print::pp::{self, break_offset, word, space, zerobreak, hardbreak};
+use syntax::print::pp::{self, break_offset, word, space, hardbreak};
use syntax::print::pp::{Breaks, eof};
use syntax::print::pp::Breaks::{Consistent, Inconsistent};
+use syntax::print::pprust::{self as ast_pp, PrintState};
use syntax::ptr::P;
use hir;
use hir::{RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
-use attr::{AttrMetaMethods, AttributeMethods};
-use std::ascii;
use std::io::{self, Write, Read};
-use std::iter;
pub enum AnnNode<'a> {
- NodeIdent(&'a ast::Ident),
NodeName(&'a ast::Name),
NodeBlock(&'a hir::Block),
NodeItem(&'a hir::Item),
}
pub trait PpAnn {
- fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { Ok(()) }
- fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { Ok(()) }
+ fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
+ Ok(())
+ }
+ fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
+ Ok(())
+ }
}
#[derive(Copy, Clone)]
impl PpAnn for NoAnn {}
-#[derive(Copy, Clone)]
-pub struct CurrentCommentAndLiteral {
- cur_cmnt: usize,
- cur_lit: usize,
-}
pub struct State<'a> {
pub s: pp::Printer<'a>,
cm: Option<&'a CodeMap>,
- comments: Option<Vec<comments::Comment> >,
- literals: Option<Vec<comments::Literal> >,
- cur_cmnt_and_lit: CurrentCommentAndLiteral,
+ comments: Option<Vec<comments::Comment>>,
+ literals: Option<Vec<comments::Literal>>,
+ cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral,
boxes: Vec<pp::Breaks>,
- ann: &'a (PpAnn+'a),
+ ann: &'a (PpAnn + 'a),
}
-pub fn rust_printer<'a>(writer: Box<Write+'a>) -> State<'a> {
+impl<'a> PrintState<'a> for State<'a> {
+ fn writer(&mut self) -> &mut pp::Printer<'a> {
+ &mut self.s
+ }
+
+ fn boxes(&mut self) -> &mut Vec<pp::Breaks> {
+ &mut self.boxes
+ }
+
+ fn comments(&mut self) -> &mut Option<Vec<comments::Comment>> {
+ &mut self.comments
+ }
+
+ fn cur_cmnt_and_lit(&mut self) -> &mut ast_pp::CurrentCommentAndLiteral {
+ &mut self.cur_cmnt_and_lit
+ }
+
+ fn literals(&self) -> &Option<Vec<comments::Literal>> {
+ &self.literals
+ }
+}
+
+pub fn rust_printer<'a>(writer: Box<Write + 'a>) -> State<'a> {
static NO_ANN: NoAnn = NoAnn;
rust_printer_annotated(writer, &NO_ANN)
}
-pub fn rust_printer_annotated<'a>(writer: Box<Write+'a>,
- ann: &'a PpAnn) -> State<'a> {
+pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>, ann: &'a PpAnn) -> State<'a> {
State {
s: pp::mk_printer(writer, default_columns),
cm: None,
comments: None,
literals: None,
- cur_cmnt_and_lit: CurrentCommentAndLiteral {
+ cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
cur_cmnt: 0,
- cur_lit: 0
+ cur_lit: 0,
},
boxes: Vec::new(),
ann: ann,
krate: &hir::Crate,
filename: String,
input: &mut Read,
- out: Box<Write+'a>,
+ out: Box<Write + 'a>,
ann: &'a PpAnn,
- is_expanded: bool) -> io::Result<()> {
- let mut s = State::new_from_input(cm,
- span_diagnostic,
- filename,
- input,
- out,
- ann,
- is_expanded);
+ is_expanded: bool)
+ -> io::Result<()> {
+ let mut s = State::new_from_input(cm, span_diagnostic, filename, input, out, ann, is_expanded);
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
span_diagnostic: &diagnostic::SpanHandler,
filename: String,
input: &mut Read,
- out: Box<Write+'a>,
+ out: Box<Write + 'a>,
ann: &'a PpAnn,
- is_expanded: bool) -> State<'a> {
- let (cmnts, lits) = comments::gather_comments_and_literals(
- span_diagnostic,
- filename,
- input);
-
- State::new(
- cm,
- out,
- ann,
- Some(cmnts),
- // If the code is post expansion, don't use the table of
- // literals, since it doesn't correspond with the literals
- // in the AST anymore.
- if is_expanded { None } else { Some(lits) })
+ is_expanded: bool)
+ -> State<'a> {
+ let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
+ filename,
+ input);
+
+ State::new(cm,
+ out,
+ ann,
+ Some(cmnts),
+ // If the code is post expansion, don't use the table of
+ // literals, since it doesn't correspond with the literals
+ // in the AST anymore.
+ if is_expanded {
+ None
+ } else {
+ Some(lits)
+ })
}
pub fn new(cm: &'a CodeMap,
- out: Box<Write+'a>,
+ out: Box<Write + 'a>,
ann: &'a PpAnn,
comments: Option<Vec<comments::Comment>>,
- literals: Option<Vec<comments::Literal>>) -> State<'a> {
+ literals: Option<Vec<comments::Literal>>)
+ -> State<'a> {
State {
s: pp::mk_printer(out, default_columns),
cm: Some(cm),
- comments: comments,
- literals: literals,
- cur_cmnt_and_lit: CurrentCommentAndLiteral {
+ comments: comments.clone(),
+ literals: literals.clone(),
+ cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
cur_cmnt: 0,
- cur_lit: 0
+ cur_lit: 0,
},
boxes: Vec::new(),
ann: ann,
}
}
-pub fn to_string<F>(f: F) -> String where
- F: FnOnce(&mut State) -> io::Result<()>,
+pub fn to_string<F>(f: F) -> String
+ where F: FnOnce(&mut State) -> io::Result<()>
{
let mut wr = Vec::new();
{
pub fn binop_to_string(op: BinOpToken) -> &'static str {
match op {
- token::Plus => "+",
- token::Minus => "-",
- token::Star => "*",
- token::Slash => "/",
- token::Percent => "%",
- token::Caret => "^",
- token::And => "&",
- token::Or => "|",
- token::Shl => "<<",
- token::Shr => ">>",
+ token::Plus => "+",
+ token::Minus => "-",
+ token::Star => "*",
+ token::Slash => "/",
+ token::Percent => "%",
+ token::Caret => "^",
+ token::And => "&",
+ token::Or => "|",
+ token::Shl => "<<",
+ token::Shr => ">>",
}
}
to_string(|s| s.print_stmt(stmt))
}
-pub fn attr_to_string(attr: &hir::Attribute) -> String {
- to_string(|s| s.print_attribute(attr))
-}
-
pub fn item_to_string(i: &hir::Item) -> String {
to_string(|s| s.print_item(i))
}
to_string(|s| s.print_path(p, false, 0))
}
-pub fn ident_to_string(id: &ast::Ident) -> String {
- to_string(|s| s.print_ident(*id))
+pub fn name_to_string(name: ast::Name) -> String {
+ to_string(|s| s.print_name(name))
}
pub fn fun_to_string(decl: &hir::FnDecl,
unsafety: hir::Unsafety,
constness: hir::Constness,
- name: ast::Ident,
+ name: ast::Name,
opt_explicit_self: Option<&hir::ExplicitSelf_>,
generics: &hir::Generics)
-> String {
to_string(|s| {
try!(s.head(""));
- try!(s.print_fn(decl, unsafety, constness, abi::Rust, Some(name),
- generics, opt_explicit_self, hir::Inherited));
+ try!(s.print_fn(decl,
+ unsafety,
+ constness,
+ abi::Rust,
+ Some(name),
+ generics,
+ opt_explicit_self,
+ hir::Inherited));
try!(s.end()); // Close the head box
s.end() // Close the outer box
})
})
}
-pub fn meta_item_to_string(mi: &hir::MetaItem) -> String {
- to_string(|s| s.print_meta_item(mi))
-}
-
-pub fn attribute_to_string(attr: &hir::Attribute) -> String {
- to_string(|s| s.print_attribute(attr))
-}
-
-pub fn lit_to_string(l: &hir::Lit) -> String {
- to_string(|s| s.print_literal(l))
-}
-
pub fn explicit_self_to_string(explicit_self: &hir::ExplicitSelf_) -> String {
to_string(|s| s.print_explicit_self(explicit_self, hir::MutImmutable).map(|_| {}))
}
pub fn visibility_qualified(vis: hir::Visibility, s: &str) -> String {
match vis {
hir::Public => format!("pub {}", s),
- hir::Inherited => s.to_string()
+ hir::Inherited => s.to_string(),
}
}
fn needs_parentheses(expr: &hir::Expr) -> bool {
match expr.node {
- hir::ExprAssign(..) | hir::ExprBinary(..) |
+ hir::ExprAssign(..) |
+ hir::ExprBinary(..) |
hir::ExprClosure(..) |
- hir::ExprAssignOp(..) | hir::ExprCast(..) => true,
+ hir::ExprAssignOp(..) |
+ hir::ExprCast(..) => true,
_ => false,
}
}
impl<'a> State<'a> {
- pub fn ibox(&mut self, u: usize) -> io::Result<()> {
- self.boxes.push(pp::Breaks::Inconsistent);
- pp::ibox(&mut self.s, u)
- }
-
- pub fn end(&mut self) -> io::Result<()> {
- self.boxes.pop().unwrap();
- pp::end(&mut self.s)
- }
-
pub fn cbox(&mut self, u: usize) -> io::Result<()> {
self.boxes.push(pp::Breaks::Consistent);
pp::cbox(&mut self.s, u)
}
- // "raw box"
- pub fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> {
- self.boxes.push(b);
- pp::rbox(&mut self.s, u, b)
+ pub fn nbsp(&mut self) -> io::Result<()> {
+ word(&mut self.s, " ")
}
- pub fn nbsp(&mut self) -> io::Result<()> { word(&mut self.s, " ") }
-
pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
try!(word(&mut self.s, w));
self.nbsp()
}
- pub fn word_space(&mut self, w: &str) -> io::Result<()> {
- try!(word(&mut self.s, w));
- space(&mut self.s)
- }
-
- pub fn popen(&mut self) -> io::Result<()> { word(&mut self.s, "(") }
-
- pub fn pclose(&mut self) -> io::Result<()> { word(&mut self.s, ")") }
-
pub fn head(&mut self, w: &str) -> io::Result<()> {
// outer-box is consistent
try!(self.cbox(indent_unit));
self.end() // close the head-box
}
- pub fn bclose_(&mut self, span: codemap::Span,
- indented: usize) -> io::Result<()> {
+ pub fn bclose_(&mut self, span: codemap::Span, indented: usize) -> io::Result<()> {
self.bclose_maybe_open(span, indented, true)
}
- pub fn bclose_maybe_open (&mut self, span: codemap::Span,
- indented: usize, close_box: bool) -> io::Result<()> {
+ pub fn bclose_maybe_open(&mut self,
+ span: codemap::Span,
+ indented: usize,
+ close_box: bool)
+ -> io::Result<()> {
try!(self.maybe_print_comment(span.hi));
try!(self.break_offset_if_not_bol(1, -(indented as isize)));
try!(word(&mut self.s, "}"));
self.bclose_(span, indent_unit)
}
- pub fn is_begin(&mut self) -> bool {
- match self.s.last_token() {
- pp::Token::Begin(_) => true,
- _ => false,
- }
- }
-
- pub fn is_end(&mut self) -> bool {
- match self.s.last_token() {
- pp::Token::End => true,
- _ => false,
- }
- }
-
- // is this the beginning of a line?
- pub fn is_bol(&mut self) -> bool {
- self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok()
- }
-
pub fn in_cbox(&self) -> bool {
match self.boxes.last() {
Some(&last_box) => last_box == pp::Breaks::Consistent,
- None => false
+ None => false,
}
}
-
- pub fn hardbreak_if_not_bol(&mut self) -> io::Result<()> {
+ pub fn space_if_not_bol(&mut self) -> io::Result<()> {
if !self.is_bol() {
- try!(hardbreak(&mut self.s))
+ try!(space(&mut self.s));
}
Ok(())
}
- pub fn space_if_not_bol(&mut self) -> io::Result<()> {
- if !self.is_bol() { try!(space(&mut self.s)); }
- Ok(())
- }
- pub fn break_offset_if_not_bol(&mut self, n: usize,
- off: isize) -> io::Result<()> {
+ pub fn break_offset_if_not_bol(&mut self, n: usize, off: isize) -> io::Result<()> {
if !self.is_bol() {
break_offset(&mut self.s, n, off)
} else {
word(&mut self.s, "*/")
}
- pub fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()> where
- F: FnMut(&mut State, &T) -> io::Result<()>,
- {
- try!(self.rbox(0, b));
- let mut first = true;
- for elt in elts {
- if first { first = false; } else { try!(self.word_space(",")); }
- try!(op(self, elt));
- }
- self.end()
- }
-
pub fn commasep_cmnt<T, F, G>(&mut self,
b: Breaks,
elts: &[T],
mut op: F,
- mut get_span: G) -> io::Result<()> where
- F: FnMut(&mut State, &T) -> io::Result<()>,
- G: FnMut(&T) -> codemap::Span,
+ mut get_span: G)
+ -> io::Result<()>
+ where F: FnMut(&mut State, &T) -> io::Result<()>,
+ G: FnMut(&T) -> codemap::Span
{
try!(self.rbox(0, b));
let len = elts.len();
i += 1;
if i < len {
try!(word(&mut self.s, ","));
- try!(self.maybe_print_trailing_comment(get_span(elt),
- Some(get_span(&elts[i]).hi)));
+ try!(self.maybe_print_trailing_comment(get_span(elt), Some(get_span(&elts[i]).hi)));
try!(self.space_if_not_bol());
}
}
self.end()
}
- pub fn commasep_exprs(&mut self, b: Breaks,
- exprs: &[P<hir::Expr>]) -> io::Result<()> {
+ pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[P<hir::Expr>]) -> io::Result<()> {
self.commasep_cmnt(b, exprs, |s, e| s.print_expr(&**e), |e| e.span)
}
- pub fn print_mod(&mut self, _mod: &hir::Mod,
- attrs: &[hir::Attribute]) -> io::Result<()> {
+ pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
try!(self.print_inner_attributes(attrs));
for item in &_mod.items {
try!(self.print_item(&**item));
Ok(())
}
- pub fn print_foreign_mod(&mut self, nmod: &hir::ForeignMod,
- attrs: &[hir::Attribute]) -> io::Result<()> {
+ pub fn print_foreign_mod(&mut self,
+ nmod: &hir::ForeignMod,
+ attrs: &[ast::Attribute])
+ -> io::Result<()> {
try!(self.print_inner_attributes(attrs));
for item in &nmod.items {
try!(self.print_foreign_item(&**item));
Ok(())
}
- pub fn print_opt_lifetime(&mut self,
- lifetime: &Option<hir::Lifetime>) -> io::Result<()> {
+ pub fn print_opt_lifetime(&mut self, lifetime: &Option<hir::Lifetime>) -> io::Result<()> {
if let Some(l) = *lifetime {
try!(self.print_lifetime(&l));
try!(self.nbsp());
}
hir::TyTup(ref elts) => {
try!(self.popen());
- try!(self.commasep(Inconsistent, &elts[..],
- |s, ty| s.print_type(&**ty)));
+ try!(self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&**ty)));
if elts.len() == 1 {
try!(word(&mut self.s, ","));
}
predicates: Vec::new(),
},
};
- try!(self.print_ty_fn(f.abi,
- f.unsafety,
- &*f.decl,
- None,
- &generics,
- None));
+ try!(self.print_ty_fn(f.abi, f.unsafety, &*f.decl, None, &generics, None));
}
hir::TyPath(None, ref path) => {
try!(self.print_path(path, false, 0));
self.end()
}
- pub fn print_foreign_item(&mut self,
- item: &hir::ForeignItem) -> io::Result<()> {
+ pub fn print_foreign_item(&mut self, item: &hir::ForeignItem) -> io::Result<()> {
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(item.span.lo));
try!(self.print_outer_attributes(&item.attrs));
match item.node {
hir::ForeignItemFn(ref decl, ref generics) => {
try!(self.head(""));
- try!(self.print_fn(decl, hir::Unsafety::Normal,
+ try!(self.print_fn(decl,
+ hir::Unsafety::Normal,
hir::Constness::NotConst,
- abi::Rust, Some(item.ident),
- generics, None, item.vis));
+ abi::Rust,
+ Some(item.name),
+ generics,
+ None,
+ item.vis));
try!(self.end()); // end head-ibox
try!(word(&mut self.s, ";"));
self.end() // end the outer fn box
}
hir::ForeignItemStatic(ref t, m) => {
- try!(self.head(&visibility_qualified(item.vis,
- "static")));
+ try!(self.head(&visibility_qualified(item.vis, "static")));
if m {
try!(self.word_space("mut"));
}
- try!(self.print_ident(item.ident));
+ try!(self.print_name(item.name));
try!(self.word_space(":"));
try!(self.print_type(&**t));
try!(word(&mut self.s, ";"));
}
fn print_associated_const(&mut self,
- ident: ast::Ident,
+ name: ast::Name,
ty: &hir::Ty,
default: Option<&hir::Expr>,
vis: hir::Visibility)
- -> io::Result<()>
- {
+ -> io::Result<()> {
try!(word(&mut self.s, &visibility_qualified(vis, "")));
try!(self.word_space("const"));
- try!(self.print_ident(ident));
+ try!(self.print_name(name));
try!(self.word_space(":"));
try!(self.print_type(ty));
if let Some(expr) = default {
}
fn print_associated_type(&mut self,
- ident: ast::Ident,
+ name: ast::Name,
bounds: Option<&hir::TyParamBounds>,
ty: Option<&hir::Ty>)
-> io::Result<()> {
try!(self.word_space("type"));
- try!(self.print_ident(ident));
+ try!(self.print_name(name));
if let Some(bounds) = bounds {
try!(self.print_bounds(":", bounds));
}
try!(self.ann.pre(self, NodeItem(item)));
match item.node {
hir::ItemExternCrate(ref optional_path) => {
- try!(self.head(&visibility_qualified(item.vis,
- "extern crate")));
+ try!(self.head(&visibility_qualified(item.vis, "extern crate")));
if let Some(p) = *optional_path {
let val = p.as_str();
if val.contains("-") {
- try!(self.print_string(&val, hir::CookedStr));
+ try!(self.print_string(&val, ast::CookedStr));
} else {
try!(self.print_name(p));
}
try!(word(&mut self.s, "as"));
try!(space(&mut self.s));
}
- try!(self.print_ident(item.ident));
+ try!(self.print_name(item.name));
try!(word(&mut self.s, ";"));
try!(self.end()); // end inner head-block
try!(self.end()); // end outer head-block
}
hir::ItemUse(ref vp) => {
- try!(self.head(&visibility_qualified(item.vis,
- "use")));
+ try!(self.head(&visibility_qualified(item.vis, "use")));
try!(self.print_view_path(&**vp));
try!(word(&mut self.s, ";"));
try!(self.end()); // end inner head-block
try!(self.end()); // end outer head-block
}
hir::ItemStatic(ref ty, m, ref expr) => {
- try!(self.head(&visibility_qualified(item.vis,
- "static")));
+ try!(self.head(&visibility_qualified(item.vis, "static")));
if m == hir::MutMutable {
try!(self.word_space("mut"));
}
- try!(self.print_ident(item.ident));
+ try!(self.print_name(item.name));
try!(self.word_space(":"));
try!(self.print_type(&**ty));
try!(space(&mut self.s));
try!(self.end()); // end the outer cbox
}
hir::ItemConst(ref ty, ref expr) => {
- try!(self.head(&visibility_qualified(item.vis,
- "const")));
- try!(self.print_ident(item.ident));
+ try!(self.head(&visibility_qualified(item.vis, "const")));
+ try!(self.print_name(item.name));
try!(self.word_space(":"));
try!(self.print_type(&**ty));
try!(space(&mut self.s));
}
hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
try!(self.head(""));
- try!(self.print_fn(
- decl,
- unsafety,
- constness,
- abi,
- Some(item.ident),
- typarams,
- None,
- item.vis
- ));
+ try!(self.print_fn(decl,
+ unsafety,
+ constness,
+ abi,
+ Some(item.name),
+ typarams,
+ None,
+ item.vis));
try!(word(&mut self.s, " "));
try!(self.print_block_with_attrs(&**body, &item.attrs));
}
hir::ItemMod(ref _mod) => {
- try!(self.head(&visibility_qualified(item.vis,
- "mod")));
- try!(self.print_ident(item.ident));
+ try!(self.head(&visibility_qualified(item.vis, "mod")));
+ try!(self.print_name(item.name));
try!(self.nbsp());
try!(self.bopen());
try!(self.print_mod(_mod, &item.attrs));
try!(self.ibox(indent_unit));
try!(self.ibox(0));
try!(self.word_nbsp(&visibility_qualified(item.vis, "type")));
- try!(self.print_ident(item.ident));
+ try!(self.print_name(item.name));
try!(self.print_generics(params));
try!(self.end()); // end the inner ibox
try!(self.end()); // end the outer ibox
}
hir::ItemEnum(ref enum_definition, ref params) => {
- try!(self.print_enum_def(
- enum_definition,
- params,
- item.ident,
- item.span,
- item.vis
- ));
+ try!(self.print_enum_def(enum_definition, params, item.name, item.span, item.vis));
}
hir::ItemStruct(ref struct_def, ref generics) => {
- try!(self.head(&visibility_qualified(item.vis,"struct")));
- try!(self.print_struct(&**struct_def, generics, item.ident, item.span));
+ try!(self.head(&visibility_qualified(item.vis, "struct")));
+ try!(self.print_struct(struct_def, generics, item.name, item.span, true));
}
hir::ItemDefaultImpl(unsafety, ref trait_ref) => {
match polarity {
hir::ImplPolarity::Negative => {
try!(word(&mut self.s, "!"));
- },
+ }
_ => {}
}
try!(self.print_visibility(item.vis));
try!(self.print_unsafety(unsafety));
try!(self.word_nbsp("trait"));
- try!(self.print_ident(item.ident));
+ try!(self.print_name(item.name));
try!(self.print_generics(generics));
let mut real_bounds = Vec::with_capacity(bounds.len());
for b in bounds.iter() {
self.print_trait_ref(&t.trait_ref)
}
- pub fn print_enum_def(&mut self, enum_definition: &hir::EnumDef,
- generics: &hir::Generics, ident: ast::Ident,
+ pub fn print_enum_def(&mut self,
+ enum_definition: &hir::EnumDef,
+ generics: &hir::Generics,
+ name: ast::Name,
span: codemap::Span,
- visibility: hir::Visibility) -> io::Result<()> {
+ visibility: hir::Visibility)
+ -> io::Result<()> {
try!(self.head(&visibility_qualified(visibility, "enum")));
- try!(self.print_ident(ident));
+ try!(self.print_name(name));
try!(self.print_generics(generics));
try!(self.print_where_clause(&generics.where_clause));
try!(space(&mut self.s));
pub fn print_variants(&mut self,
variants: &[P<hir::Variant>],
- span: codemap::Span) -> io::Result<()> {
+ span: codemap::Span)
+ -> io::Result<()> {
try!(self.bopen());
for v in variants {
try!(self.space_if_not_bol());
pub fn print_visibility(&mut self, vis: hir::Visibility) -> io::Result<()> {
match vis {
hir::Public => self.word_nbsp("pub"),
- hir::Inherited => Ok(())
+ hir::Inherited => Ok(()),
}
}
pub fn print_struct(&mut self,
- struct_def: &hir::StructDef,
+ struct_def: &hir::VariantData,
generics: &hir::Generics,
- ident: ast::Ident,
- span: codemap::Span) -> io::Result<()> {
- try!(self.print_ident(ident));
+ name: ast::Name,
+ span: codemap::Span,
+ print_finalizer: bool)
+ -> io::Result<()> {
+ try!(self.print_name(name));
try!(self.print_generics(generics));
- if ::util::struct_def_is_tuple_like(struct_def) {
- if !struct_def.fields.is_empty() {
+ if !struct_def.is_struct() {
+ if struct_def.is_tuple() {
try!(self.popen());
- try!(self.commasep(
- Inconsistent, &struct_def.fields,
- |s, field| {
- match field.node.kind {
- hir::NamedField(..) => panic!("unexpected named field"),
- hir::UnnamedField(vis) => {
- try!(s.print_visibility(vis));
- try!(s.maybe_print_comment(field.span.lo));
- s.print_type(&*field.node.ty)
- }
- }
- }
- ));
+ try!(self.commasep(Inconsistent,
+ struct_def.fields(),
+ |s, field| {
+ match field.node.kind {
+ hir::NamedField(..) => panic!("unexpected named field"),
+ hir::UnnamedField(vis) => {
+ try!(s.print_visibility(vis));
+ try!(s.maybe_print_comment(field.span.lo));
+ s.print_type(&*field.node.ty)
+ }
+ }
+ }));
try!(self.pclose());
}
try!(self.print_where_clause(&generics.where_clause));
- try!(word(&mut self.s, ";"));
+ if print_finalizer {
+ try!(word(&mut self.s, ";"));
+ }
try!(self.end());
self.end() // close the outer-box
} else {
try!(self.bopen());
try!(self.hardbreak_if_not_bol());
- for field in &struct_def.fields {
+ for field in struct_def.fields() {
match field.node.kind {
hir::UnnamedField(..) => panic!("unexpected unnamed field"),
- hir::NamedField(ident, visibility) => {
+ hir::NamedField(name, visibility) => {
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(field.span.lo));
try!(self.print_outer_attributes(&field.node.attrs));
try!(self.print_visibility(visibility));
- try!(self.print_ident(ident));
+ try!(self.print_name(name));
try!(self.word_nbsp(":"));
try!(self.print_type(&*field.node.ty));
try!(word(&mut self.s, ","));
}
pub fn print_variant(&mut self, v: &hir::Variant) -> io::Result<()> {
- try!(self.print_visibility(v.node.vis));
- match v.node.kind {
- hir::TupleVariantKind(ref args) => {
- try!(self.print_ident(v.node.name));
- if !args.is_empty() {
- try!(self.popen());
- try!(self.commasep(Consistent,
- &args[..],
- |s, arg| s.print_type(&*arg.ty)));
- try!(self.pclose());
- }
- }
- hir::StructVariantKind(ref struct_def) => {
- try!(self.head(""));
- let generics = ::util::empty_generics();
- try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
- }
- }
+ try!(self.head(""));
+ let generics = ::util::empty_generics();
+ try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false));
match v.node.disr_expr {
Some(ref d) => {
try!(space(&mut self.s));
try!(self.word_space("="));
self.print_expr(&**d)
}
- _ => Ok(())
+ _ => Ok(()),
}
}
pub fn print_method_sig(&mut self,
- ident: ast::Ident,
+ name: ast::Name,
m: &hir::MethodSig,
vis: hir::Visibility)
-> io::Result<()> {
m.unsafety,
m.constness,
m.abi,
- Some(ident),
+ Some(name),
&m.generics,
Some(&m.explicit_self.node),
vis)
}
- pub fn print_trait_item(&mut self, ti: &hir::TraitItem)
- -> io::Result<()> {
+ pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> {
try!(self.ann.pre(self, NodeSubItem(ti.id)));
try!(self.hardbreak_if_not_bol());
try!(self.maybe_print_comment(ti.span.lo));
try!(self.print_outer_attributes(&ti.attrs));
match ti.node {
hir::ConstTraitItem(ref ty, ref default) => {
- try!(self.print_associated_const(ti.ident, &ty,
+ try!(self.print_associated_const(ti.name,
+ &ty,
default.as_ref().map(|expr| &**expr),
hir::Inherited));
}
if body.is_some() {
try!(self.head(""));
}
- try!(self.print_method_sig(ti.ident, sig, hir::Inherited));
+ try!(self.print_method_sig(ti.name, sig, hir::Inherited));
if let Some(ref body) = *body {
try!(self.nbsp());
try!(self.print_block_with_attrs(body, &ti.attrs));
}
}
hir::TypeTraitItem(ref bounds, ref default) => {
- try!(self.print_associated_type(ti.ident, Some(bounds),
+ try!(self.print_associated_type(ti.name,
+ Some(bounds),
default.as_ref().map(|ty| &**ty)));
}
}
try!(self.print_outer_attributes(&ii.attrs));
match ii.node {
hir::ConstImplItem(ref ty, ref expr) => {
- try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));
+ try!(self.print_associated_const(ii.name, &ty, Some(&expr), ii.vis));
}
hir::MethodImplItem(ref sig, ref body) => {
try!(self.head(""));
- try!(self.print_method_sig(ii.ident, sig, ii.vis));
+ try!(self.print_method_sig(ii.name, sig, ii.vis));
try!(self.nbsp());
try!(self.print_block_with_attrs(body, &ii.attrs));
}
hir::TypeImplItem(ref ty) => {
- try!(self.print_associated_type(ii.ident, None, Some(ty)));
+ try!(self.print_associated_type(ii.name, None, Some(ty)));
}
}
self.ann.post(self, NodeSubItem(ii.id))
}
- pub fn print_outer_attributes(&mut self,
- attrs: &[hir::Attribute]) -> io::Result<()> {
- let mut count = 0;
- for attr in attrs {
- match attr.node.style {
- hir::AttrOuter => {
- try!(self.print_attribute(attr));
- count += 1;
- }
- _ => {/* fallthrough */ }
- }
- }
- if count > 0 {
- try!(self.hardbreak_if_not_bol());
- }
- Ok(())
- }
-
- pub fn print_inner_attributes(&mut self,
- attrs: &[hir::Attribute]) -> io::Result<()> {
- let mut count = 0;
- for attr in attrs {
- match attr.node.style {
- hir::AttrInner => {
- try!(self.print_attribute(attr));
- count += 1;
- }
- _ => {/* fallthrough */ }
- }
- }
- if count > 0 {
- try!(self.hardbreak_if_not_bol());
- }
- Ok(())
- }
-
- pub fn print_attribute(&mut self, attr: &hir::Attribute) -> io::Result<()> {
- try!(self.hardbreak_if_not_bol());
- try!(self.maybe_print_comment(attr.span.lo));
- if attr.node.is_sugared_doc {
- word(&mut self.s, &attr.value_str().unwrap())
- } else {
- match attr.node.style {
- hir::AttrInner => try!(word(&mut self.s, "#![")),
- hir::AttrOuter => try!(word(&mut self.s, "#[")),
- }
- try!(self.print_meta_item(&*attr.meta()));
- word(&mut self.s, "]")
- }
- }
-
-
pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> {
try!(self.maybe_print_comment(st.span.lo));
match st.node {
self.print_block_unclosed_indent(blk, indent_unit)
}
- pub fn print_block_unclosed_indent(&mut self, blk: &hir::Block,
- indented: usize) -> io::Result<()> {
+ pub fn print_block_unclosed_indent(&mut self,
+ blk: &hir::Block,
+ indented: usize)
+ -> io::Result<()> {
self.print_block_maybe_unclosed(blk, indented, &[], false)
}
pub fn print_block_with_attrs(&mut self,
blk: &hir::Block,
- attrs: &[hir::Attribute]) -> io::Result<()> {
+ attrs: &[ast::Attribute])
+ -> io::Result<()> {
self.print_block_maybe_unclosed(blk, indent_unit, attrs, true)
}
pub fn print_block_maybe_unclosed(&mut self,
blk: &hir::Block,
indented: usize,
- attrs: &[hir::Attribute],
- close_box: bool) -> io::Result<()> {
+ attrs: &[ast::Attribute],
+ close_box: bool)
+ -> io::Result<()> {
match blk.rules {
- hir::UnsafeBlock(..) | hir::PushUnsafeBlock(..) => try!(self.word_space("unsafe")),
- hir::DefaultBlock | hir::PopUnsafeBlock(..) => ()
+ hir::UnsafeBlock(..) => try!(self.word_space("unsafe")),
+ hir::PushUnsafeBlock(..) => try!(self.word_space("push_unsafe")),
+ hir::PopUnsafeBlock(..) => try!(self.word_space("pop_unsafe")),
+ hir::PushUnstableBlock => try!(self.word_space("push_unstable")),
+ hir::PopUnstableBlock => try!(self.word_space("pop_unstable")),
+ hir::DefaultBlock => (),
}
try!(self.maybe_print_comment(blk.span.lo));
try!(self.ann.pre(self, NodeBlock(blk)));
try!(self.print_expr(&**expr));
try!(self.maybe_print_trailing_comment(expr.span, Some(blk.span.hi)));
}
- _ => ()
+ _ => (),
}
try!(self.bclose_maybe_open(blk.span, indented, close_box));
self.ann.post(self, NodeBlock(blk))
}
}
}
- _ => Ok(())
+ _ => Ok(()),
}
}
- pub fn print_if(&mut self, test: &hir::Expr, blk: &hir::Block,
- elseopt: Option<&hir::Expr>) -> io::Result<()> {
+ pub fn print_if(&mut self,
+ test: &hir::Expr,
+ blk: &hir::Block,
+ elseopt: Option<&hir::Expr>)
+ -> io::Result<()> {
try!(self.head("if"));
try!(self.print_expr(test));
try!(space(&mut self.s));
self.print_else(elseopt)
}
- pub fn print_if_let(&mut self, pat: &hir::Pat, expr: &hir::Expr, blk: &hir::Block,
- elseopt: Option<&hir::Expr>) -> io::Result<()> {
+ pub fn print_if_let(&mut self,
+ pat: &hir::Pat,
+ expr: &hir::Expr,
+ blk: &hir::Block,
+ elseopt: Option<&hir::Expr>)
+ -> io::Result<()> {
try!(self.head("if let"));
try!(self.print_pat(pat));
try!(space(&mut self.s));
Ok(())
}
- fn print_expr_box(&mut self,
- place: &Option<P<hir::Expr>>,
- expr: &hir::Expr) -> io::Result<()> {
- try!(word(&mut self.s, "box"));
- try!(word(&mut self.s, "("));
- try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
- try!(self.word_space(")"));
- self.print_expr(expr)
- }
-
fn print_expr_vec(&mut self, exprs: &[P<hir::Expr>]) -> io::Result<()> {
try!(self.ibox(indent_unit));
try!(word(&mut self.s, "["));
self.end()
}
- fn print_expr_repeat(&mut self,
- element: &hir::Expr,
- count: &hir::Expr) -> io::Result<()> {
+ fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> {
try!(self.ibox(indent_unit));
try!(word(&mut self.s, "["));
try!(self.print_expr(element));
fn print_expr_struct(&mut self,
path: &hir::Path,
fields: &[hir::Field],
- wth: &Option<P<hir::Expr>>) -> io::Result<()> {
+ wth: &Option<P<hir::Expr>>)
+ -> io::Result<()> {
try!(self.print_path(path, true, 0));
- if !(fields.is_empty() && wth.is_none()) {
- try!(word(&mut self.s, "{"));
- try!(self.commasep_cmnt(
- Consistent,
- &fields[..],
- |s, field| {
- try!(s.ibox(indent_unit));
- try!(s.print_ident(field.ident.node));
- try!(s.word_space(":"));
- try!(s.print_expr(&*field.expr));
- s.end()
- },
- |f| f.span));
- match *wth {
- Some(ref expr) => {
- try!(self.ibox(indent_unit));
- if !fields.is_empty() {
- try!(word(&mut self.s, ","));
- try!(space(&mut self.s));
- }
- try!(word(&mut self.s, ".."));
- try!(self.print_expr(&**expr));
- try!(self.end());
+ try!(word(&mut self.s, "{"));
+ try!(self.commasep_cmnt(Consistent,
+ &fields[..],
+ |s, field| {
+ try!(s.ibox(indent_unit));
+ try!(s.print_name(field.name.node));
+ try!(s.word_space(":"));
+ try!(s.print_expr(&*field.expr));
+ s.end()
+ },
+ |f| f.span));
+ match *wth {
+ Some(ref expr) => {
+ try!(self.ibox(indent_unit));
+ if !fields.is_empty() {
+ try!(word(&mut self.s, ","));
+ try!(space(&mut self.s));
}
- _ => try!(word(&mut self.s, ",")),
+ try!(word(&mut self.s, ".."));
+ try!(self.print_expr(&**expr));
+ try!(self.end());
}
- try!(word(&mut self.s, "}"));
+ _ => if !fields.is_empty() {
+ try!(word(&mut self.s, ","))
+ },
}
+ try!(word(&mut self.s, "}"));
Ok(())
}
self.pclose()
}
- fn print_expr_call(&mut self,
- func: &hir::Expr,
- args: &[P<hir::Expr>]) -> io::Result<()> {
+ fn print_expr_call(&mut self, func: &hir::Expr, args: &[P<hir::Expr>]) -> io::Result<()> {
try!(self.print_expr_maybe_paren(func));
self.print_call_post(args)
}
fn print_expr_method_call(&mut self,
- ident: hir::SpannedIdent,
+ name: Spanned<ast::Name>,
tys: &[P<hir::Ty>],
- args: &[P<hir::Expr>]) -> io::Result<()> {
+ args: &[P<hir::Expr>])
+ -> io::Result<()> {
let base_args = &args[1..];
try!(self.print_expr(&*args[0]));
try!(word(&mut self.s, "."));
- try!(self.print_ident(ident.node));
+ try!(self.print_name(name.node));
if !tys.is_empty() {
try!(word(&mut self.s, "::<"));
- try!(self.commasep(Inconsistent, tys,
- |s, ty| s.print_type(&**ty)));
+ try!(self.commasep(Inconsistent, tys, |s, ty| s.print_type(&**ty)));
try!(word(&mut self.s, ">"));
}
self.print_call_post(base_args)
fn print_expr_binary(&mut self,
op: hir::BinOp,
lhs: &hir::Expr,
- rhs: &hir::Expr) -> io::Result<()> {
+ rhs: &hir::Expr)
+ -> io::Result<()> {
try!(self.print_expr(lhs));
try!(space(&mut self.s));
try!(self.word_space(::util::binop_to_string(op.node)));
self.print_expr(rhs)
}
- fn print_expr_unary(&mut self,
- op: hir::UnOp,
- expr: &hir::Expr) -> io::Result<()> {
+ fn print_expr_unary(&mut self, op: hir::UnOp, expr: &hir::Expr) -> io::Result<()> {
try!(word(&mut self.s, ::util::unop_to_string(op)));
self.print_expr_maybe_paren(expr)
}
fn print_expr_addr_of(&mut self,
mutability: hir::Mutability,
- expr: &hir::Expr) -> io::Result<()> {
+ expr: &hir::Expr)
+ -> io::Result<()> {
try!(word(&mut self.s, "&"));
try!(self.print_mutability(mutability));
self.print_expr_maybe_paren(expr)
try!(self.ibox(indent_unit));
try!(self.ann.pre(self, NodeExpr(expr)));
match expr.node {
- hir::ExprBox(ref place, ref expr) => {
- try!(self.print_expr_box(place, &**expr));
+ hir::ExprBox(ref expr) => {
+ try!(self.word_space("box"));
+ try!(self.print_expr(expr));
}
hir::ExprVec(ref exprs) => {
try!(self.print_expr_vec(&exprs[..]));
hir::ExprCall(ref func, ref args) => {
try!(self.print_expr_call(&**func, &args[..]));
}
- hir::ExprMethodCall(ident, ref tys, ref args) => {
- try!(self.print_expr_method_call(ident, &tys[..], &args[..]));
+ hir::ExprMethodCall(name, ref tys, ref args) => {
+ try!(self.print_expr_method_call(name, &tys[..], &args[..]));
}
hir::ExprBinary(op, ref lhs, ref rhs) => {
try!(self.print_expr_binary(op, &**lhs, &**rhs));
}
hir::ExprWhile(ref test, ref blk, opt_ident) => {
if let Some(ident) = opt_ident {
- try!(self.print_ident(ident));
+ try!(self.print_name(ident.name));
try!(self.word_space(":"));
}
try!(self.head("while"));
}
hir::ExprLoop(ref blk, opt_ident) => {
if let Some(ident) = opt_ident {
- try!(self.print_ident(ident));
+ try!(self.print_name(ident.name));
try!(self.word_space(":"));
}
try!(self.head("loop"));
let default_return = match decl.output {
hir::DefaultReturn(..) => true,
- _ => false
+ _ => false,
};
if !default_return || !body.stmts.is_empty() || body.expr.is_none() {
try!(self.word_space("="));
try!(self.print_expr(&**rhs));
}
- hir::ExprField(ref expr, id) => {
+ hir::ExprField(ref expr, name) => {
try!(self.print_expr(&**expr));
try!(word(&mut self.s, "."));
- try!(self.print_ident(id.node));
+ try!(self.print_name(name.node));
}
hir::ExprTupField(ref expr, id) => {
try!(self.print_expr(&**expr));
try!(word(&mut self.s, "break"));
try!(space(&mut self.s));
if let Some(ident) = opt_ident {
- try!(self.print_ident(ident.node));
+ try!(self.print_name(ident.node.name));
try!(space(&mut self.s));
}
}
try!(word(&mut self.s, "continue"));
try!(space(&mut self.s));
if let Some(ident) = opt_ident {
- try!(self.print_ident(ident.node));
+ try!(self.print_name(ident.node.name));
try!(space(&mut self.s))
}
}
try!(word(&mut self.s, " "));
try!(self.print_expr(&**expr));
}
- _ => ()
+ _ => (),
}
}
hir::ExprInlineAsm(ref a) => {
try!(self.print_string(&a.asm, a.asm_str_style));
try!(self.word_space(":"));
- try!(self.commasep(Inconsistent, &a.outputs,
+ try!(self.commasep(Inconsistent,
+ &a.outputs,
|s, &(ref co, ref o, is_rw)| {
- match co.slice_shift_char() {
- Some(('=', operand)) if is_rw => {
- try!(s.print_string(&format!("+{}", operand),
- hir::CookedStr))
- }
- _ => try!(s.print_string(&co, hir::CookedStr))
- }
- try!(s.popen());
- try!(s.print_expr(&**o));
- try!(s.pclose());
- Ok(())
- }));
+ match co.slice_shift_char() {
+ Some(('=', operand)) if is_rw => {
+ try!(s.print_string(&format!("+{}", operand),
+ ast::CookedStr))
+ }
+ _ => try!(s.print_string(&co, ast::CookedStr)),
+ }
+ try!(s.popen());
+ try!(s.print_expr(&**o));
+ try!(s.pclose());
+ Ok(())
+ }));
try!(space(&mut self.s));
try!(self.word_space(":"));
- try!(self.commasep(Inconsistent, &a.inputs,
+ try!(self.commasep(Inconsistent,
+ &a.inputs,
|s, &(ref co, ref o)| {
- try!(s.print_string(&co, hir::CookedStr));
- try!(s.popen());
- try!(s.print_expr(&**o));
- try!(s.pclose());
- Ok(())
- }));
+ try!(s.print_string(&co, ast::CookedStr));
+ try!(s.popen());
+ try!(s.print_expr(&**o));
+ try!(s.pclose());
+ Ok(())
+ }));
try!(space(&mut self.s));
try!(self.word_space(":"));
- try!(self.commasep(Inconsistent, &a.clobbers,
+ try!(self.commasep(Inconsistent,
+ &a.clobbers,
|s, co| {
- try!(s.print_string(&co, hir::CookedStr));
- Ok(())
- }));
+ try!(s.print_string(&co, ast::CookedStr));
+ Ok(())
+ }));
let mut options = vec!();
if a.volatile {
if a.alignstack {
options.push("alignstack");
}
- if a.dialect == hir::AsmDialect::AsmIntel {
+ if a.dialect == ast::AsmDialect::Intel {
options.push("intel");
}
if !options.is_empty() {
try!(space(&mut self.s));
try!(self.word_space(":"));
- try!(self.commasep(Inconsistent, &*options,
+ try!(self.commasep(Inconsistent,
+ &*options,
|s, &co| {
- try!(s.print_string(co, hir::CookedStr));
- Ok(())
- }));
+ try!(s.print_string(co, ast::CookedStr));
+ Ok(())
+ }));
}
try!(self.pclose());
}
- hir::ExprParen(ref e) => {
- try!(self.popen());
- try!(self.print_expr(&**e));
- try!(self.pclose());
- }
}
try!(self.ann.post(self, NodeExpr(expr)));
self.end()
}
self.end()
}
- hir::DeclItem(ref item) => self.print_item(&**item)
+ hir::DeclItem(ref item) => self.print_item(&**item),
}
}
- pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
- try!(word(&mut self.s, &ident.name.as_str()));
- self.ann.post(self, NodeIdent(&ident))
- }
-
pub fn print_usize(&mut self, i: usize) -> io::Result<()> {
word(&mut self.s, &i.to_string())
}
self.ann.post(self, NodeName(&name))
}
- pub fn print_for_decl(&mut self, loc: &hir::Local,
- coll: &hir::Expr) -> io::Result<()> {
+ pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) -> io::Result<()> {
try!(self.print_local_decl(loc));
try!(space(&mut self.s));
try!(self.word_space("in"));
path: &hir::Path,
colons_before_params: bool,
depth: usize)
- -> io::Result<()>
- {
+ -> io::Result<()> {
try!(self.maybe_print_comment(path.span.lo));
let mut first = !path.global;
try!(word(&mut self.s, "::"))
}
- try!(self.print_ident(segment.identifier));
+ try!(self.print_name(segment.identifier.name));
try!(self.print_path_parameters(&segment.parameters, colons_before_params));
}
path: &hir::Path,
qself: &hir::QSelf,
colons_before_params: bool)
- -> io::Result<()>
- {
+ -> io::Result<()> {
try!(word(&mut self.s, "<"));
try!(self.print_type(&qself.ty));
if qself.position > 0 {
try!(word(&mut self.s, ">"));
try!(word(&mut self.s, "::"));
let item_segment = path.segments.last().unwrap();
- try!(self.print_ident(item_segment.identifier));
+ try!(self.print_name(item_segment.identifier.name));
self.print_path_parameters(&item_segment.parameters, colons_before_params)
}
fn print_path_parameters(&mut self,
parameters: &hir::PathParameters,
colons_before_params: bool)
- -> io::Result<()>
- {
+ -> io::Result<()> {
if parameters.is_empty() {
return Ok(());
}
if comma {
try!(self.word_space(","))
}
- try!(self.commasep(
- Inconsistent,
- &data.types,
- |s, ty| s.print_type(&**ty)));
- comma = true;
+ try!(self.commasep(Inconsistent, &data.types, |s, ty| s.print_type(&**ty)));
+ comma = true;
}
for binding in data.bindings.iter() {
if comma {
try!(self.word_space(","))
}
- try!(self.print_ident(binding.ident));
+ try!(self.print_name(binding.name));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_type(&*binding.ty));
hir::ParenthesizedParameters(ref data) => {
try!(word(&mut self.s, "("));
- try!(self.commasep(
- Inconsistent,
- &data.inputs,
- |s, ty| s.print_type(&**ty)));
+ try!(self.commasep(Inconsistent,
+ &data.inputs,
+ |s, ty| s.print_type(&**ty)));
try!(word(&mut self.s, ")"));
match data.output {
- None => { }
+ None => {}
Some(ref ty) => {
try!(self.space_if_not_bol());
try!(self.word_space("->"));
try!(self.word_nbsp("mut"));
}
}
- try!(self.print_ident(path1.node));
+ try!(self.print_name(path1.node.name));
match *sub {
Some(ref p) => {
try!(word(&mut self.s, "@"));
try!(self.print_pat(&**p));
}
- None => ()
+ None => (),
}
}
hir::PatEnum(ref path, ref args_) => {
Some(ref args) => {
if !args.is_empty() {
try!(self.popen());
- try!(self.commasep(Inconsistent, &args[..],
- |s, p| s.print_pat(&**p)));
+ try!(self.commasep(Inconsistent, &args[..], |s, p| s.print_pat(&**p)));
try!(self.pclose());
}
}
try!(self.print_path(path, true, 0));
try!(self.nbsp());
try!(self.word_space("{"));
- try!(self.commasep_cmnt(
- Consistent, &fields[..],
- |s, f| {
- try!(s.cbox(indent_unit));
- if !f.node.is_shorthand {
- try!(s.print_ident(f.node.ident));
- try!(s.word_nbsp(":"));
- }
- try!(s.print_pat(&*f.node.pat));
- s.end()
- },
- |f| f.node.pat.span));
+ try!(self.commasep_cmnt(Consistent,
+ &fields[..],
+ |s, f| {
+ try!(s.cbox(indent_unit));
+ if !f.node.is_shorthand {
+ try!(s.print_name(f.node.name));
+ try!(s.word_nbsp(":"));
+ }
+ try!(s.print_pat(&*f.node.pat));
+ s.end()
+ },
+ |f| f.node.pat.span));
if etc {
- if !fields.is_empty() { try!(self.word_space(",")); }
+ if !fields.is_empty() {
+ try!(self.word_space(","));
+ }
try!(word(&mut self.s, ".."));
}
try!(space(&mut self.s));
}
hir::PatTup(ref elts) => {
try!(self.popen());
- try!(self.commasep(Inconsistent,
- &elts[..],
- |s, p| s.print_pat(&**p)));
+ try!(self.commasep(Inconsistent, &elts[..], |s, p| s.print_pat(&**p)));
if elts.len() == 1 {
try!(word(&mut self.s, ","));
}
}
hir::PatVec(ref before, ref slice, ref after) => {
try!(word(&mut self.s, "["));
- try!(self.commasep(Inconsistent,
- &before[..],
- |s, p| s.print_pat(&**p)));
+ try!(self.commasep(Inconsistent, &before[..], |s, p| s.print_pat(&**p)));
if let Some(ref p) = *slice {
- if !before.is_empty() { try!(self.word_space(",")); }
+ if !before.is_empty() {
+ try!(self.word_space(","));
+ }
try!(self.print_pat(&**p));
match **p {
hir::Pat { node: hir::PatWild(hir::PatWildMulti), .. } => {
}
_ => try!(word(&mut self.s, "..")),
}
- if !after.is_empty() { try!(self.word_space(",")); }
+ if !after.is_empty() {
+ try!(self.word_space(","));
+ }
}
- try!(self.commasep(Inconsistent,
- &after[..],
- |s, p| s.print_pat(&**p)));
+ try!(self.commasep(Inconsistent, &after[..], |s, p| s.print_pat(&**p)));
try!(word(&mut self.s, "]"));
}
}
// Returns whether it printed anything
fn print_explicit_self(&mut self,
explicit_self: &hir::ExplicitSelf_,
- mutbl: hir::Mutability) -> io::Result<bool> {
+ mutbl: hir::Mutability)
+ -> io::Result<bool> {
try!(self.print_mutability(mutbl));
match *explicit_self {
- hir::SelfStatic => { return Ok(false); }
+ hir::SelfStatic => {
+ return Ok(false);
+ }
hir::SelfValue(_) => {
try!(word(&mut self.s, "self"));
}
unsafety: hir::Unsafety,
constness: hir::Constness,
abi: abi::Abi,
- name: Option<ast::Ident>,
+ name: Option<ast::Name>,
generics: &hir::Generics,
opt_explicit_self: Option<&hir::ExplicitSelf_>,
- vis: hir::Visibility) -> io::Result<()> {
+ vis: hir::Visibility)
+ -> io::Result<()> {
try!(self.print_fn_header_info(unsafety, constness, abi, vis));
if let Some(name) = name {
try!(self.nbsp());
- try!(self.print_ident(name));
+ try!(self.print_name(name));
}
try!(self.print_generics(generics));
try!(self.print_fn_args_and_ret(decl, opt_explicit_self));
self.print_where_clause(&generics.where_clause)
}
- pub fn print_fn_args(&mut self, decl: &hir::FnDecl,
+ pub fn print_fn_args(&mut self,
+ decl: &hir::FnDecl,
opt_explicit_self: Option<&hir::ExplicitSelf_>)
- -> io::Result<()> {
+ -> io::Result<()> {
// It is unfortunate to duplicate the commasep logic, but we want the
// self type and the args all in the same box.
try!(self.rbox(0, Inconsistent));
&hir::SelfStatic => hir::MutImmutable,
_ => match decl.inputs[0].pat.node {
hir::PatIdent(hir::BindByValue(m), _, _) => m,
- _ => hir::MutImmutable
- }
+ _ => hir::MutImmutable,
+ },
};
first = !try!(self.print_explicit_self(explicit_self, m));
}
};
for arg in args {
- if first { first = false; } else { try!(self.word_space(",")); }
+ if first {
+ first = false;
+ } else {
+ try!(self.word_space(","));
+ }
try!(self.print_arg(arg));
}
self.end()
}
- pub fn print_fn_args_and_ret(&mut self, decl: &hir::FnDecl,
+ pub fn print_fn_args_and_ret(&mut self,
+ decl: &hir::FnDecl,
opt_explicit_self: Option<&hir::ExplicitSelf_>)
- -> io::Result<()> {
+ -> io::Result<()> {
try!(self.popen());
try!(self.print_fn_args(decl, opt_explicit_self));
if decl.variadic {
self.print_fn_output(decl)
}
- pub fn print_fn_block_args(
- &mut self,
- decl: &hir::FnDecl)
- -> io::Result<()> {
+ pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
try!(word(&mut self.s, "|"));
try!(self.print_fn_args(decl, None));
try!(word(&mut self.s, "|"));
}
}
- pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureClause)
- -> io::Result<()> {
+ pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureClause) -> io::Result<()> {
match capture_clause {
hir::CaptureByValue => self.word_space("move"),
hir::CaptureByRef => Ok(()),
}
}
- pub fn print_bounds(&mut self,
- prefix: &str,
- bounds: &[hir::TyParamBound])
- -> io::Result<()> {
+ pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io::Result<()> {
if !bounds.is_empty() {
try!(word(&mut self.s, prefix));
let mut first = true;
}
}
- pub fn print_lifetime(&mut self,
- lifetime: &hir::Lifetime)
- -> io::Result<()>
- {
+ pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> {
self.print_name(lifetime.name)
}
- pub fn print_lifetime_def(&mut self,
- lifetime: &hir::LifetimeDef)
- -> io::Result<()>
- {
+ pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> {
try!(self.print_lifetime(&lifetime.lifetime));
let mut sep = ":";
for v in &lifetime.bounds {
Ok(())
}
- pub fn print_generics(&mut self,
- generics: &hir::Generics)
- -> io::Result<()>
- {
+ pub fn print_generics(&mut self, generics: &hir::Generics) -> io::Result<()> {
let total = generics.lifetimes.len() + generics.ty_params.len();
if total == 0 {
return Ok(());
ints.push(i);
}
- try!(self.commasep(Inconsistent, &ints[..], |s, &idx| {
- if idx < generics.lifetimes.len() {
- let lifetime = &generics.lifetimes[idx];
- s.print_lifetime_def(lifetime)
- } else {
- let idx = idx - generics.lifetimes.len();
- let param = &generics.ty_params[idx];
- s.print_ty_param(param)
- }
- }));
+ try!(self.commasep(Inconsistent,
+ &ints[..],
+ |s, &idx| {
+ if idx < generics.lifetimes.len() {
+ let lifetime = &generics.lifetimes[idx];
+ s.print_lifetime_def(lifetime)
+ } else {
+ let idx = idx - generics.lifetimes.len();
+ let param = &generics.ty_params[idx];
+ s.print_ty_param(param)
+ }
+ }));
try!(word(&mut self.s, ">"));
Ok(())
}
pub fn print_ty_param(&mut self, param: &hir::TyParam) -> io::Result<()> {
- try!(self.print_ident(param.ident));
+ try!(self.print_name(param.name));
try!(self.print_bounds(":", ¶m.bounds));
match param.default {
Some(ref default) => {
try!(self.word_space("="));
self.print_type(&**default)
}
- _ => Ok(())
+ _ => Ok(()),
}
}
- pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause)
- -> io::Result<()> {
+ pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) -> io::Result<()> {
if where_clause.predicates.is_empty() {
return Ok(())
}
Ok(())
}
- pub fn print_meta_item(&mut self, item: &hir::MetaItem) -> io::Result<()> {
- try!(self.ibox(indent_unit));
- match item.node {
- hir::MetaWord(ref name) => {
- try!(word(&mut self.s, &name));
- }
- hir::MetaNameValue(ref name, ref value) => {
- try!(self.word_space(&name[..]));
- try!(self.word_space("="));
- try!(self.print_literal(value));
- }
- hir::MetaList(ref name, ref items) => {
- try!(word(&mut self.s, &name));
- try!(self.popen());
- try!(self.commasep(Consistent,
- &items[..],
- |s, i| s.print_meta_item(&**i)));
- try!(self.pclose());
- }
- }
- self.end()
- }
-
pub fn print_view_path(&mut self, vp: &hir::ViewPath) -> io::Result<()> {
match vp.node {
- hir::ViewPathSimple(ident, ref path) => {
+ hir::ViewPathSimple(name, ref path) => {
try!(self.print_path(path, false, 0));
- // FIXME(#6993) can't compare identifiers directly here
- if path.segments.last().unwrap().identifier.name !=
- ident.name {
+ if path.segments.last().unwrap().identifier.name != name {
try!(space(&mut self.s));
try!(self.word_space("as"));
- try!(self.print_ident(ident));
+ try!(self.print_name(name));
}
Ok(())
word(&mut self.s, "::*")
}
- hir::ViewPathList(ref path, ref idents) => {
+ hir::ViewPathList(ref path, ref segments) => {
if path.segments.is_empty() {
try!(word(&mut self.s, "{"));
} else {
try!(self.print_path(path, false, 0));
try!(word(&mut self.s, "::{"));
}
- try!(self.commasep(Inconsistent, &idents[..], |s, w| {
- match w.node {
- hir::PathListIdent { name, .. } => {
- s.print_ident(name)
- },
- hir::PathListMod { .. } => {
- word(&mut s.s, "self")
- }
- }
- }));
+ try!(self.commasep(Inconsistent,
+ &segments[..],
+ |s, w| {
+ match w.node {
+ hir::PathListIdent { name, .. } => {
+ s.print_name(name)
+ }
+ hir::PathListMod { .. } => {
+ word(&mut s.s, "self")
+ }
+ }
+ }));
word(&mut self.s, "}")
}
}
}
- pub fn print_mutability(&mut self,
- mutbl: hir::Mutability) -> io::Result<()> {
+ pub fn print_mutability(&mut self, mutbl: hir::Mutability) -> io::Result<()> {
match mutbl {
hir::MutMutable => self.word_nbsp("mut"),
hir::MutImmutable => Ok(()),
try!(self.ibox(indent_unit));
try!(self.word_space("->"));
match decl.output {
- hir::NoReturn(_) =>
- try!(self.word_nbsp("!")),
+ hir::NoReturn(_) => try!(self.word_nbsp("!")),
hir::DefaultReturn(..) => unreachable!(),
- hir::Return(ref ty) =>
- try!(self.print_type(&**ty))
+ hir::Return(ref ty) => try!(self.print_type(&**ty)),
}
try!(self.end());
match decl.output {
hir::Return(ref output) => self.maybe_print_comment(output.span.lo),
- _ => Ok(())
+ _ => Ok(()),
}
}
abi: abi::Abi,
unsafety: hir::Unsafety,
decl: &hir::FnDecl,
- name: Option<ast::Ident>,
+ name: Option<ast::Name>,
generics: &hir::Generics,
opt_explicit_self: Option<&hir::ExplicitSelf_>)
-> io::Result<()> {
self.end()
}
- pub fn maybe_print_trailing_comment(&mut self, span: codemap::Span,
+ pub fn maybe_print_trailing_comment(&mut self,
+ span: codemap::Span,
next_pos: Option<BytePos>)
- -> io::Result<()> {
+ -> io::Result<()> {
let cm = match self.cm {
Some(cm) => cm,
- _ => return Ok(())
+ _ => return Ok(()),
};
match self.next_comment() {
Some(ref cmnt) => {
- if (*cmnt).style != comments::Trailing { return Ok(()) }
+ if (*cmnt).style != comments::Trailing {
+ return Ok(())
+ }
let span_line = cm.lookup_char_pos(span.hi);
let comment_line = cm.lookup_char_pos((*cmnt).pos);
let mut next = (*cmnt).pos + BytePos(1);
- match next_pos { None => (), Some(p) => next = p }
+ match next_pos {
+ None => (),
+ Some(p) => next = p,
+ }
if span.hi < (*cmnt).pos && (*cmnt).pos < next &&
- span_line.line == comment_line.line {
- try!(self.print_comment(cmnt));
- self.cur_cmnt_and_lit.cur_cmnt += 1;
- }
+ span_line.line == comment_line.line {
+ try!(self.print_comment(cmnt));
+ self.cur_cmnt_and_lit.cur_cmnt += 1;
+ }
}
- _ => ()
+ _ => (),
}
Ok(())
}
try!(self.print_comment(cmnt));
self.cur_cmnt_and_lit.cur_cmnt += 1;
}
- _ => break
- }
- }
- Ok(())
- }
-
- pub fn print_literal(&mut self, lit: &hir::Lit) -> io::Result<()> {
- try!(self.maybe_print_comment(lit.span.lo));
- match self.next_lit(lit.span.lo) {
- Some(ref ltrl) => {
- return word(&mut self.s, &(*ltrl).lit);
- }
- _ => ()
- }
- match lit.node {
- hir::LitStr(ref st, style) => self.print_string(&st, style),
- hir::LitByte(byte) => {
- let mut res = String::from("b'");
- res.extend(ascii::escape_default(byte).map(|c| c as char));
- res.push('\'');
- word(&mut self.s, &res[..])
- }
- hir::LitChar(ch) => {
- let mut res = String::from("'");
- res.extend(ch.escape_default());
- res.push('\'');
- word(&mut self.s, &res[..])
- }
- hir::LitInt(i, t) => {
- match t {
- hir::SignedIntLit(st, hir::Plus) => {
- word(&mut self.s,
- &::util::int_ty_to_string(st, Some(i as i64)))
- }
- hir::SignedIntLit(st, hir::Minus) => {
- let istr = ::util::int_ty_to_string(st, Some(-(i as i64)));
- word(&mut self.s,
- &format!("-{}", istr))
- }
- hir::UnsignedIntLit(ut) => {
- word(&mut self.s, &::util::uint_ty_to_string(ut, Some(i)))
- }
- hir::UnsuffixedIntLit(hir::Plus) => {
- word(&mut self.s, &format!("{}", i))
- }
- hir::UnsuffixedIntLit(hir::Minus) => {
- word(&mut self.s, &format!("-{}", i))
- }
- }
- }
- hir::LitFloat(ref f, t) => {
- word(&mut self.s,
- &format!(
- "{}{}",
- &f,
- &::util::float_ty_to_string(t)))
- }
- hir::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[..]),
- hir::LitBool(val) => {
- if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") }
- }
- hir::LitByteStr(ref v) => {
- let mut escaped: String = String::new();
- for &ch in v.iter() {
- escaped.extend(ascii::escape_default(ch)
- .map(|c| c as char));
- }
- word(&mut self.s, &format!("b\"{}\"", escaped))
- }
- }
- }
-
- pub fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
- match self.literals {
- Some(ref lits) => {
- while self.cur_cmnt_and_lit.cur_lit < lits.len() {
- let ltrl = (*lits)[self.cur_cmnt_and_lit.cur_lit].clone();
- if ltrl.pos > pos { return None; }
- self.cur_cmnt_and_lit.cur_lit += 1;
- if ltrl.pos == pos { return Some(ltrl); }
- }
- None
- }
- _ => None
- }
- }
-
- pub fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
- loop {
- match self.next_comment() {
- Some(ref cmnt) => {
- if (*cmnt).pos < pos {
- try!(self.print_comment(cmnt));
- self.cur_cmnt_and_lit.cur_cmnt += 1;
- } else { break; }
- }
- _ => break
+ _ => break,
}
}
Ok(())
}
- pub fn print_comment(&mut self,
- cmnt: &comments::Comment) -> io::Result<()> {
- match cmnt.style {
- comments::Mixed => {
- assert_eq!(cmnt.lines.len(), 1);
- try!(zerobreak(&mut self.s));
- try!(word(&mut self.s, &cmnt.lines[0]));
- zerobreak(&mut self.s)
- }
- comments::Isolated => {
- try!(self.hardbreak_if_not_bol());
- for line in &cmnt.lines {
- // Don't print empty lines because they will end up as trailing
- // whitespace
- if !line.is_empty() {
- try!(word(&mut self.s, &line[..]));
- }
- try!(hardbreak(&mut self.s));
- }
- Ok(())
- }
- comments::Trailing => {
- try!(word(&mut self.s, " "));
- if cmnt.lines.len() == 1 {
- try!(word(&mut self.s, &cmnt.lines[0]));
- hardbreak(&mut self.s)
- } else {
- try!(self.ibox(0));
- for line in &cmnt.lines {
- if !line.is_empty() {
- try!(word(&mut self.s, &line[..]));
- }
- try!(hardbreak(&mut self.s));
- }
- self.end()
- }
- }
- comments::BlankLine => {
- // We need to do at least one, possibly two hardbreaks.
- let is_semi = match self.s.last_token() {
- pp::Token::String(s, _) => ";" == s,
- _ => false
- };
- if is_semi || self.is_begin() || self.is_end() {
- try!(hardbreak(&mut self.s));
- }
- hardbreak(&mut self.s)
- }
- }
- }
-
- pub fn print_string(&mut self, st: &str,
- style: hir::StrStyle) -> io::Result<()> {
- let st = match style {
- hir::CookedStr => {
- (format!("\"{}\"", st.escape_default()))
- }
- hir::RawStr(n) => {
- (format!("r{delim}\"{string}\"{delim}",
- delim=repeat("#", n),
- string=st))
- }
- };
- word(&mut self.s, &st[..])
- }
-
- pub fn next_comment(&mut self) -> Option<comments::Comment> {
- match self.comments {
- Some(ref cmnts) => {
- if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() {
- Some(cmnts[self.cur_cmnt_and_lit.cur_cmnt].clone())
- } else {
- None
- }
- }
- _ => None
- }
- }
-
pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
opt_abi: Option<abi::Abi>)
- -> io::Result<()> {
+ -> io::Result<()> {
match opt_abi {
Some(abi::Rust) => Ok(()),
Some(abi) => {
try!(self.word_nbsp("extern"));
self.word_nbsp(&abi.to_string())
}
- None => Ok(())
+ None => Ok(()),
}
}
- pub fn print_extern_opt_abi(&mut self,
- opt_abi: Option<abi::Abi>) -> io::Result<()> {
+ pub fn print_extern_opt_abi(&mut self, opt_abi: Option<abi::Abi>) -> io::Result<()> {
match opt_abi {
Some(abi) => {
try!(self.word_nbsp("extern"));
self.word_nbsp(&abi.to_string())
}
- None => Ok(())
+ None => Ok(()),
}
}
unsafety: hir::Unsafety,
constness: hir::Constness,
abi: abi::Abi,
- vis: hir::Visibility) -> io::Result<()> {
+ vis: hir::Visibility)
+ -> io::Result<()> {
try!(word(&mut self.s, &visibility_qualified(vis, "")));
try!(self.print_unsafety(unsafety));
match constness {
hir::Constness::NotConst => {}
- hir::Constness::Const => try!(self.word_nbsp("const"))
+ hir::Constness::Const => try!(self.word_nbsp("const")),
}
if abi != abi::Rust {
}
}
-fn repeat(s: &str, n: usize) -> String { iter::repeat(s).take(n).collect() }
-
// Dup'ed from parse::classify, but adapted for the HIR.
/// Does this expression require a semicolon to be treated
/// as a statement? The negation of this: 'can this expression
/// isn't parsed as (if true {...} else {...} | x) | 5
fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool {
match e.node {
- hir::ExprIf(..)
- | hir::ExprMatch(..)
- | hir::ExprBlock(_)
- | hir::ExprWhile(..)
- | hir::ExprLoop(..) => false,
- _ => true
+ hir::ExprIf(..) |
+ hir::ExprMatch(..) |
+ hir::ExprBlock(_) |
+ hir::ExprWhile(..) |
+ hir::ExprLoop(..) => false,
+ _ => true,
}
}
hir::StmtDecl(ref d, _) => {
match d.node {
hir::DeclLocal(_) => true,
- hir::DeclItem(_) => false
+ hir::DeclItem(_) => false,
}
}
- hir::StmtExpr(ref e, _) => { expr_requires_semi_to_be_stmt(&**e) }
- hir::StmtSemi(..) => { false }
+ hir::StmtExpr(ref e, _) => {
+ expr_requires_semi_to_be_stmt(&**e)
+ }
+ hir::StmtSemi(..) => {
+ false
+ }
}
}
use hir::*;
use visit::{self, Visitor, FnKind};
use syntax::ast_util;
-use syntax::ast::{Ident, NodeId, DUMMY_NODE_ID};
+use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID};
use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::owned_slice::OwnedSlice;
-pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool {
+pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool
+ where F: FnMut(&Pat) -> bool
+{
// FIXME(#19596) this is a workaround, but there should be a better way
- fn walk_pat_<G>(pat: &Pat, it: &mut G) -> bool where G: FnMut(&Pat) -> bool {
+ fn walk_pat_<G>(pat: &Pat, it: &mut G) -> bool
+ where G: FnMut(&Pat) -> bool
+ {
if !(*it)(pat) {
return false;
}
slice.iter().all(|p| walk_pat_(&**p, it)) &&
after.iter().all(|p| walk_pat_(&**p, it))
}
- PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
- PatEnum(_, _) | PatQPath(_, _) => {
+ PatWild(_) |
+ PatLit(_) |
+ PatRange(_, _) |
+ PatIdent(_, _, _) |
+ PatEnum(_, _) |
+ PatQPath(_, _) => {
true
}
}
BiLe => "<=",
BiNe => "!=",
BiGe => ">=",
- BiGt => ">"
+ BiGt => ">",
}
}
-/// Returns true if the given struct def is tuple-like; i.e. that its fields
-/// are unnamed.
-pub fn struct_def_is_tuple_like(struct_def: &hir::StructDef) -> bool {
- struct_def.ctor_id.is_some()
-}
-
pub fn stmt_id(s: &Stmt) -> NodeId {
match s.node {
- StmtDecl(_, id) => id,
- StmtExpr(_, id) => id,
- StmtSemi(_, id) => id,
+ StmtDecl(_, id) => id,
+ StmtExpr(_, id) => id,
+ StmtSemi(_, id) => id,
}
}
pub fn lazy_binop(b: BinOp_) -> bool {
match b {
- BiAnd => true,
- BiOr => true,
- _ => false
+ BiAnd => true,
+ BiOr => true,
+ _ => false,
}
}
pub fn is_shift_binop(b: BinOp_) -> bool {
match b {
- BiShl => true,
- BiShr => true,
- _ => false
+ BiShl => true,
+ BiShr => true,
+ _ => false,
}
}
pub fn is_comparison_binop(b: BinOp_) -> bool {
match b {
- BiEq | BiLt | BiLe | BiNe | BiGt | BiGe =>
- true,
- BiAnd | BiOr | BiAdd | BiSub | BiMul | BiDiv | BiRem |
- BiBitXor | BiBitAnd | BiBitOr | BiShl | BiShr =>
- false,
+ BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true,
+ BiAnd |
+ BiOr |
+ BiAdd |
+ BiSub |
+ BiMul |
+ BiDiv |
+ BiRem |
+ BiBitXor |
+ BiBitAnd |
+ BiBitOr |
+ BiShl |
+ BiShr => false,
}
}
pub fn unop_to_string(op: UnOp) -> &'static str {
match op {
- UnUniq => "box() ",
- UnDeref => "*",
- UnNot => "!",
- UnNeg => "-",
+ UnDeref => "*",
+ UnNot => "!",
+ UnNeg => "-",
}
}
-pub struct IdVisitor<'a, O:'a> {
+pub struct IdVisitor<'a, O: 'a> {
pub operation: &'a mut O,
pub pass_through_items: bool,
pub visited_outermost: bool,
}
impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
- fn visit_mod(&mut self,
- module: &Mod,
- _: Span,
- node_id: NodeId) {
+ fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) {
self.operation.visit_id(node_id);
visit::walk_mod(self, module)
}
}
}
}
- ItemEnum(ref enum_definition, _) => {
- for variant in &enum_definition.variants {
- self.operation.visit_id(variant.node.id)
- }
- }
_ => {}
}
self.operation.visit_id(argument.id)
}
- visit::walk_fn(self,
- function_kind,
- function_declaration,
- block,
- span);
+ visit::walk_fn(self, function_kind, function_declaration, block, span);
if !self.pass_through_items {
if let FnKind::Method(..) = function_kind {
visit::walk_struct_field(self, struct_field)
}
- fn visit_struct_def(&mut self,
- struct_def: &StructDef,
- _: Ident,
+ fn visit_variant_data(&mut self,
+ struct_def: &VariantData,
+ _: Name,
_: &hir::Generics,
- id: NodeId) {
- self.operation.visit_id(id);
- struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
+ _: NodeId,
+ _: Span) {
+ self.operation.visit_id(struct_def.id());
visit::walk_struct_def(self, struct_def);
}
visit::walk_impl_item(self, ii);
}
- fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) {
+ fn visit_lifetime(&mut self, lifetime: &Lifetime) {
self.operation.visit_id(lifetime.id);
}
fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
- self.visit_lifetime_ref(&def.lifetime);
+ self.visit_lifetime(&def.lifetime);
}
fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
body: &Block,
sp: Span,
id: NodeId)
- -> ast_util::IdRange
-{
- let mut visitor = ast_util::IdRangeComputingVisitor {
- result: ast_util::IdRange::max()
- };
+ -> ast_util::IdRange {
+ let mut visitor = ast_util::IdRangeComputingVisitor { result: ast_util::IdRange::max() };
let mut id_visitor = IdVisitor {
operation: &mut visitor,
pass_through_items: false,
id_visitor.operation.result
}
-/// Returns true if this literal is a string and false otherwise.
-pub fn lit_is_str(lit: &Lit) -> bool {
- match lit.node {
- LitStr(..) => true,
- _ => false,
- }
-}
-
pub fn is_path(e: P<Expr>) -> bool {
- match e.node { ExprPath(..) => true, _ => false }
-}
-
-/// Get a string representation of a signed int type, with its value.
-/// We want to avoid "45int" and "-3int" in favor of "45" and "-3"
-pub fn int_ty_to_string(t: IntTy, val: Option<i64>) -> String {
- let s = match t {
- TyIs => "isize",
- TyI8 => "i8",
- TyI16 => "i16",
- TyI32 => "i32",
- TyI64 => "i64"
- };
-
- match val {
- // cast to a u64 so we can correctly print INT64_MIN. All integral types
- // are parsed as u64, so we wouldn't want to print an extra negative
- // sign.
- Some(n) => format!("{}{}", n as u64, s),
- None => s.to_string()
- }
-}
-
-
-/// Get a string representation of an unsigned int type, with its value.
-/// We want to avoid "42u" in favor of "42us". "42uint" is right out.
-pub fn uint_ty_to_string(t: UintTy, val: Option<u64>) -> String {
- let s = match t {
- TyUs => "usize",
- TyU8 => "u8",
- TyU16 => "u16",
- TyU32 => "u32",
- TyU64 => "u64"
- };
-
- match val {
- Some(n) => format!("{}{}", n, s),
- None => s.to_string()
- }
-}
-
-pub fn float_ty_to_string(t: FloatTy) -> String {
- match t {
- TyF32 => "f32".to_string(),
- TyF64 => "f64".to_string(),
+ match e.node {
+ ExprPath(..) => true,
+ _ => false,
}
}
-
pub fn empty_generics() -> Generics {
Generics {
lifetimes: Vec::new(),
where_clause: WhereClause {
id: DUMMY_NODE_ID,
predicates: Vec::new(),
- }
+ },
}
}
// convert a span and an identifier to the corresponding
// 1-segment path
-pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
+pub fn ident_to_path(s: Span, ident: Ident) -> Path {
hir::Path {
span: s,
global: false,
- segments: vec!(
- hir::PathSegment {
- identifier: identifier,
- parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
- bindings: OwnedSlice::empty(),
- })
- }
- ),
+ segments: vec!(hir::PathSegment {
+ identifier: ident,
+ parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
+ lifetimes: Vec::new(),
+ types: OwnedSlice::empty(),
+ bindings: OwnedSlice::empty(),
+ }),
+ }),
}
}
//! those that are created by the expansion of a macro.
use syntax::abi::Abi;
-use syntax::ast::{Ident, NodeId, CRATE_NODE_ID, Name};
-use hir::*;
-use hir;
+use syntax::ast::{Ident, NodeId, CRATE_NODE_ID, Name, Attribute};
use syntax::codemap::Span;
-use syntax::ptr::P;
-use syntax::owned_slice::OwnedSlice;
+use hir::*;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum FnKind<'a> {
/// fn foo() or extern "Abi" fn foo()
- ItemFn(Ident, &'a Generics, Unsafety, Constness, Abi, Visibility),
+ ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, Visibility),
/// fn foo(&self)
- Method(Ident, &'a MethodSig, Option<Visibility>),
+ Method(Name, &'a MethodSig, Option<Visibility>),
- /// |x, y| ...
- /// proc(x, y) ...
+ /// |x, y| {}
Closure,
}
// Nothing to do.
}
fn visit_ident(&mut self, span: Span, ident: Ident) {
- self.visit_name(span, ident.name);
- }
- fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) }
- fn visit_foreign_item(&mut self, i: &'v ForeignItem) { walk_foreign_item(self, i) }
- fn visit_item(&mut self, i: &'v Item) { walk_item(self, i) }
- fn visit_local(&mut self, l: &'v Local) { walk_local(self, l) }
- fn visit_block(&mut self, b: &'v Block) { walk_block(self, b) }
- fn visit_stmt(&mut self, s: &'v Stmt) { walk_stmt(self, s) }
- fn visit_arm(&mut self, a: &'v Arm) { walk_arm(self, a) }
- fn visit_pat(&mut self, p: &'v Pat) { walk_pat(self, p) }
- fn visit_decl(&mut self, d: &'v Decl) { walk_decl(self, d) }
- fn visit_expr(&mut self, ex: &'v Expr) { walk_expr(self, ex) }
- fn visit_expr_post(&mut self, _ex: &'v Expr) { }
- fn visit_ty(&mut self, t: &'v Ty) { walk_ty(self, t) }
- fn visit_generics(&mut self, g: &'v Generics) { walk_generics(self, g) }
+ walk_ident(self, span, ident);
+ }
+ fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) {
+ walk_mod(self, m)
+ }
+ fn visit_foreign_item(&mut self, i: &'v ForeignItem) {
+ walk_foreign_item(self, i)
+ }
+ fn visit_item(&mut self, i: &'v Item) {
+ walk_item(self, i)
+ }
+ fn visit_local(&mut self, l: &'v Local) {
+ walk_local(self, l)
+ }
+ fn visit_block(&mut self, b: &'v Block) {
+ walk_block(self, b)
+ }
+ fn visit_stmt(&mut self, s: &'v Stmt) {
+ walk_stmt(self, s)
+ }
+ fn visit_arm(&mut self, a: &'v Arm) {
+ walk_arm(self, a)
+ }
+ fn visit_pat(&mut self, p: &'v Pat) {
+ walk_pat(self, p)
+ }
+ fn visit_decl(&mut self, d: &'v Decl) {
+ walk_decl(self, d)
+ }
+ fn visit_expr(&mut self, ex: &'v Expr) {
+ walk_expr(self, ex)
+ }
+ fn visit_expr_post(&mut self, _ex: &'v Expr) {
+ }
+ fn visit_ty(&mut self, t: &'v Ty) {
+ walk_ty(self, t)
+ }
+ fn visit_generics(&mut self, g: &'v Generics) {
+ walk_generics(self, g)
+ }
fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: &'v Block, s: Span, _: NodeId) {
walk_fn(self, fk, fd, b, s)
}
- fn visit_trait_item(&mut self, ti: &'v TraitItem) { walk_trait_item(self, ti) }
- fn visit_impl_item(&mut self, ii: &'v ImplItem) { walk_impl_item(self, ii) }
- fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) }
+ fn visit_trait_item(&mut self, ti: &'v TraitItem) {
+ walk_trait_item(self, ti)
+ }
+ fn visit_impl_item(&mut self, ii: &'v ImplItem) {
+ walk_impl_item(self, ii)
+ }
+ fn visit_trait_ref(&mut self, t: &'v TraitRef) {
+ walk_trait_ref(self, t)
+ }
fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) {
walk_ty_param_bound(self, bounds)
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
- fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) {
+ fn visit_variant_data(&mut self, s: &'v VariantData, _: Name,
+ _: &'v Generics, _: NodeId, _: Span) {
walk_struct_def(self, s)
}
- fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) }
- fn visit_enum_def(&mut self, enum_definition: &'v EnumDef,
- generics: &'v Generics) {
- walk_enum_def(self, enum_definition, generics)
+ fn visit_struct_field(&mut self, s: &'v StructField) {
+ walk_struct_field(self, s)
}
-
- fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) }
-
- /// Visits an optional reference to a lifetime. The `span` is the span of some surrounding
- /// reference should opt_lifetime be None.
- fn visit_opt_lifetime_ref(&mut self,
- _span: Span,
- opt_lifetime: &'v Option<Lifetime>) {
- match *opt_lifetime {
- Some(ref l) => self.visit_lifetime_ref(l),
- None => ()
- }
+ fn visit_enum_def(&mut self, enum_definition: &'v EnumDef,
+ generics: &'v Generics, item_id: NodeId, _: Span) {
+ walk_enum_def(self, enum_definition, generics, item_id)
}
- fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) {
- walk_lifetime_bound(self, lifetime)
+ fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
+ walk_variant(self, v, g, item_id)
}
- fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) {
- walk_lifetime_ref(self, lifetime)
+ fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
+ walk_lifetime(self, lifetime)
}
fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) {
walk_lifetime_def(self, lifetime)
fn visit_path(&mut self, path: &'v Path, _id: NodeId) {
walk_path(self, path)
}
+ fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) {
+ walk_path_list_item(self, prefix, item)
+ }
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) {
walk_path_segment(self, path_span, path_segment)
}
fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) {
walk_assoc_type_binding(self, type_binding)
}
- fn visit_attribute(&mut self, _attr: &'v Attribute) {}
+ fn visit_attribute(&mut self, _attr: &'v Attribute) {
+ }
+ fn visit_macro_def(&mut self, macro_def: &'v MacroDef) {
+ walk_macro_def(self, macro_def)
+ }
}
-pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
- visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
- for attr in &krate.attrs {
- visitor.visit_attribute(attr);
+pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
+ for name in opt_name {
+ visitor.visit_name(span, name);
}
}
-pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
- for item in &module.items {
- visitor.visit_item(&**item)
+pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option<Ident>) {
+ for ident in opt_ident {
+ visitor.visit_ident(span, ident);
}
}
-pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
- visitor.visit_pat(&*local.pat);
- walk_ty_opt(visitor, &local.ty);
- walk_expr_opt(visitor, &local.init);
+pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) {
+ visitor.visit_name(span, ident.name);
}
-pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetime_def: &'v LifetimeDef) {
- visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name);
- for bound in &lifetime_def.bounds {
- visitor.visit_lifetime_bound(bound);
- }
+pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
+ visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
+ walk_list!(visitor, visit_attribute, &krate.attrs);
+ walk_list!(visitor, visit_macro_def, &krate.exported_macros);
+}
+
+pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) {
+ visitor.visit_name(macro_def.span, macro_def.name);
+ walk_opt_name(visitor, macro_def.span, macro_def.imported_from);
+ walk_list!(visitor, visit_attribute, ¯o_def.attrs);
+}
+
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
+ walk_list!(visitor, visit_item, &module.items);
}
-pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetime_ref: &'v Lifetime) {
- visitor.visit_lifetime_ref(lifetime_ref)
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
+ visitor.visit_pat(&local.pat);
+ walk_list!(visitor, visit_ty, &local.ty);
+ walk_list!(visitor, visit_expr, &local.init);
+}
+
+pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
+ visitor.visit_name(lifetime.span, lifetime.name);
}
-pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetime_ref: &'v Lifetime) {
- visitor.visit_name(lifetime_ref.span, lifetime_ref.name)
+pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v LifetimeDef) {
+ visitor.visit_lifetime(&lifetime_def.lifetime);
+ walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
}
-pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V,
- explicit_self: &'v ExplicitSelf) {
+pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V, explicit_self: &'v ExplicitSelf) {
match explicit_self.node {
- SelfStatic | SelfValue(_) => {},
- SelfRegion(ref lifetime, _, _) => {
- visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime)
+ SelfStatic => {}
+ SelfValue(name) => {
+ visitor.visit_name(explicit_self.span, name)
+ }
+ SelfRegion(ref opt_lifetime, _, name) => {
+ visitor.visit_name(explicit_self.span, name);
+ walk_list!(visitor, visit_lifetime, opt_lifetime);
+ }
+ SelfExplicit(ref typ, name) => {
+ visitor.visit_name(explicit_self.span, name);
+ visitor.visit_ty(typ)
}
- SelfExplicit(ref typ, _) => visitor.visit_ty(&**typ),
}
}
_modifier: &'v TraitBoundModifier)
where V: Visitor<'v>
{
- walk_lifetime_decls_helper(visitor, &trait_ref.bound_lifetimes);
+ walk_list!(visitor,
+ visit_lifetime_def,
+ &trait_ref.bound_lifetimes);
visitor.visit_trait_ref(&trait_ref.trait_ref);
}
-pub fn walk_trait_ref<'v,V>(visitor: &mut V,
- trait_ref: &'v TraitRef)
+pub fn walk_trait_ref<'v, V>(visitor: &mut V, trait_ref: &'v TraitRef)
where V: Visitor<'v>
{
visitor.visit_path(&trait_ref.path, trait_ref.ref_id)
}
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
- visitor.visit_ident(item.span, item.ident);
+ visitor.visit_name(item.span, item.name);
match item.node {
- ItemExternCrate(..) => {}
+ ItemExternCrate(opt_name) => {
+ walk_opt_name(visitor, item.span, opt_name)
+ }
ItemUse(ref vp) => {
match vp.node {
- ViewPathSimple(ident, ref path) => {
- visitor.visit_ident(vp.span, ident);
+ ViewPathSimple(name, ref path) => {
+ visitor.visit_name(vp.span, name);
visitor.visit_path(path, item.id);
}
ViewPathGlob(ref path) => {
visitor.visit_path(path, item.id);
}
ViewPathList(ref prefix, ref list) => {
- for id in list {
- match id.node {
- PathListIdent { name, .. } => {
- visitor.visit_ident(id.span, name);
- }
- PathListMod { .. } => ()
+ if !list.is_empty() {
+ for item in list {
+ visitor.visit_path_list_item(prefix, item)
}
+ } else {
+ visitor.visit_path(prefix, item.id);
}
-
- // Note that the `prefix` here is not a complete
- // path, so we don't use `visit_path`.
- walk_path(visitor, prefix);
}
}
}
ItemStatic(ref typ, _, ref expr) |
ItemConst(ref typ, ref expr) => {
- visitor.visit_ty(&**typ);
- visitor.visit_expr(&**expr);
+ visitor.visit_ty(typ);
+ visitor.visit_expr(expr);
}
ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
- visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety,
- constness, abi, item.vis),
- &**declaration,
- &**body,
+ visitor.visit_fn(FnKind::ItemFn(item.name,
+ generics,
+ unsafety,
+ constness,
+ abi,
+ item.vis),
+ declaration,
+ body,
item.span,
item.id)
}
visitor.visit_mod(module, item.span, item.id)
}
ItemForeignMod(ref foreign_module) => {
- for foreign_item in &foreign_module.items {
- visitor.visit_foreign_item(&**foreign_item)
- }
+ walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemTy(ref typ, ref type_parameters) => {
- visitor.visit_ty(&**typ);
+ visitor.visit_ty(typ);
visitor.visit_generics(type_parameters)
}
ItemEnum(ref enum_definition, ref type_parameters) => {
visitor.visit_generics(type_parameters);
- visitor.visit_enum_def(enum_definition, type_parameters)
+ visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
}
ItemDefaultImpl(_, ref trait_ref) => {
visitor.visit_trait_ref(trait_ref)
}
ItemImpl(_, _,
ref type_parameters,
- ref trait_reference,
+ ref opt_trait_reference,
ref typ,
ref impl_items) => {
visitor.visit_generics(type_parameters);
- match *trait_reference {
- Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference),
- None => ()
- }
- visitor.visit_ty(&**typ);
- for impl_item in impl_items {
- visitor.visit_impl_item(impl_item);
- }
+ walk_list!(visitor, visit_trait_ref, opt_trait_reference);
+ visitor.visit_ty(typ);
+ walk_list!(visitor, visit_impl_item, impl_items);
}
ItemStruct(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
- visitor.visit_struct_def(&**struct_definition,
- item.ident,
- generics,
- item.id)
+ visitor.visit_variant_data(struct_definition, item.name,
+ generics, item.id, item.span);
}
ItemTrait(_, ref generics, ref bounds, ref methods) => {
visitor.visit_generics(generics);
- walk_ty_param_bounds_helper(visitor, bounds);
- for method in methods {
- visitor.visit_trait_item(method)
- }
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_trait_item, methods);
}
}
- for attr in &item.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_list!(visitor, visit_attribute, &item.attrs);
}
pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
enum_definition: &'v EnumDef,
- generics: &'v Generics) {
- for variant in &enum_definition.variants {
- visitor.visit_variant(&**variant, generics);
- }
+ generics: &'v Generics,
+ item_id: NodeId) {
+ walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id);
}
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
variant: &'v Variant,
- generics: &'v Generics) {
- visitor.visit_ident(variant.span, variant.node.name);
-
- match variant.node.kind {
- TupleVariantKind(ref variant_arguments) => {
- for variant_argument in variant_arguments {
- visitor.visit_ty(&*variant_argument.ty)
- }
- }
- StructVariantKind(ref struct_definition) => {
- visitor.visit_struct_def(&**struct_definition,
- variant.node.name,
- generics,
- variant.node.id)
- }
- }
- match variant.node.disr_expr {
- Some(ref expr) => visitor.visit_expr(&**expr),
- None => ()
- }
- for attr in &variant.node.attrs {
- visitor.visit_attribute(attr);
- }
-}
-
-pub fn skip_ty<'v, V: Visitor<'v>>(_: &mut V, _: &'v Ty) {
- // Empty!
-}
-
-pub fn walk_ty_opt<'v, V: Visitor<'v>>(visitor: &mut V, optional_type: &'v Option<P<Ty>>) {
- match *optional_type {
- Some(ref ty) => visitor.visit_ty(&**ty),
- None => ()
- }
+ generics: &'v Generics,
+ item_id: NodeId) {
+ visitor.visit_name(variant.span, variant.node.name);
+ visitor.visit_variant_data(&variant.node.data, variant.node.name,
+ generics, item_id, variant.span);
+ walk_list!(visitor, visit_expr, &variant.node.disr_expr);
+ walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
match typ.node {
TyVec(ref ty) | TyParen(ref ty) => {
- visitor.visit_ty(&**ty)
+ visitor.visit_ty(ty)
}
TyPtr(ref mutable_type) => {
- visitor.visit_ty(&*mutable_type.ty)
+ visitor.visit_ty(&mutable_type.ty)
}
- TyRptr(ref lifetime, ref mutable_type) => {
- visitor.visit_opt_lifetime_ref(typ.span, lifetime);
- visitor.visit_ty(&*mutable_type.ty)
+ TyRptr(ref opt_lifetime, ref mutable_type) => {
+ walk_list!(visitor, visit_lifetime, opt_lifetime);
+ visitor.visit_ty(&mutable_type.ty)
}
TyTup(ref tuple_element_types) => {
- for tuple_element_type in tuple_element_types {
- visitor.visit_ty(&**tuple_element_type)
- }
+ walk_list!(visitor, visit_ty, tuple_element_types);
}
TyBareFn(ref function_declaration) => {
- for argument in &function_declaration.decl.inputs {
- visitor.visit_ty(&*argument.ty)
- }
- walk_fn_ret_ty(visitor, &function_declaration.decl.output);
- walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes);
+ walk_fn_decl(visitor, &function_declaration.decl);
+ walk_list!(visitor,
+ visit_lifetime_def,
+ &function_declaration.lifetimes);
}
TyPath(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself {
visitor.visit_path(path, typ.id);
}
TyObjectSum(ref ty, ref bounds) => {
- visitor.visit_ty(&**ty);
- walk_ty_param_bounds_helper(visitor, bounds);
+ visitor.visit_ty(ty);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
}
TyFixedLengthVec(ref ty, ref expression) => {
- visitor.visit_ty(&**ty);
- visitor.visit_expr(&**expression)
+ visitor.visit_ty(ty);
+ visitor.visit_expr(expression)
}
TyPolyTraitRef(ref bounds) => {
- walk_ty_param_bounds_helper(visitor, bounds)
+ walk_list!(visitor, visit_ty_param_bound, bounds);
}
TyTypeof(ref expression) => {
- visitor.visit_expr(&**expression)
+ visitor.visit_expr(expression)
}
TyInfer => {}
}
}
-pub fn walk_lifetime_decls_helper<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetimes: &'v Vec<LifetimeDef>) {
- for l in lifetimes {
- visitor.visit_lifetime_def(l);
- }
-}
-
pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
for segment in &path.segments {
visitor.visit_path_segment(path.span, segment);
}
}
+pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V,
+ prefix: &'v Path,
+ item: &'v PathListItem) {
+ for segment in &prefix.segments {
+ visitor.visit_path_segment(prefix.span, segment);
+ }
+
+ walk_opt_name(visitor, item.span, item.node.name());
+ walk_opt_name(visitor, item.span, item.node.rename());
+}
+
pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
path_span: Span,
segment: &'v PathSegment) {
_path_span: Span,
path_parameters: &'v PathParameters) {
match *path_parameters {
- hir::AngleBracketedParameters(ref data) => {
- for typ in data.types.iter() {
- visitor.visit_ty(&**typ);
- }
- for lifetime in &data.lifetimes {
- visitor.visit_lifetime_ref(lifetime);
- }
- for binding in data.bindings.iter() {
- visitor.visit_assoc_type_binding(&**binding);
- }
+ AngleBracketedParameters(ref data) => {
+ walk_list!(visitor, visit_ty, &data.types);
+ walk_list!(visitor, visit_lifetime, &data.lifetimes);
+ walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
}
- hir::ParenthesizedParameters(ref data) => {
- for typ in &data.inputs {
- visitor.visit_ty(&**typ);
- }
- if let Some(ref typ) = data.output {
- visitor.visit_ty(&**typ);
- }
+ ParenthesizedParameters(ref data) => {
+ walk_list!(visitor, visit_ty, &data.inputs);
+ walk_list!(visitor, visit_ty, &data.output);
}
}
}
pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
type_binding: &'v TypeBinding) {
- visitor.visit_ident(type_binding.span, type_binding.ident);
- visitor.visit_ty(&*type_binding.ty);
+ visitor.visit_name(type_binding.span, type_binding.name);
+ visitor.visit_ty(&type_binding.ty);
}
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
match pattern.node {
- PatEnum(ref path, ref children) => {
+ PatEnum(ref path, ref opt_children) => {
visitor.visit_path(path, pattern.id);
- if let Some(ref children) = *children {
- for child in children {
- visitor.visit_pat(&*child)
- }
+ if let Some(ref children) = *opt_children {
+ walk_list!(visitor, visit_pat, children);
}
}
PatQPath(ref qself, ref path) => {
PatStruct(ref path, ref fields, _) => {
visitor.visit_path(path, pattern.id);
for field in fields {
- visitor.visit_pat(&*field.node.pat)
+ visitor.visit_name(field.span, field.node.name);
+ visitor.visit_pat(&field.node.pat)
}
}
PatTup(ref tuple_elements) => {
- for tuple_element in tuple_elements {
- visitor.visit_pat(&**tuple_element)
- }
+ walk_list!(visitor, visit_pat, tuple_elements);
}
PatBox(ref subpattern) |
PatRegion(ref subpattern, _) => {
- visitor.visit_pat(&**subpattern)
+ visitor.visit_pat(subpattern)
}
PatIdent(_, ref pth1, ref optional_subpattern) => {
visitor.visit_ident(pth1.span, pth1.node);
- match *optional_subpattern {
- None => {}
- Some(ref subpattern) => visitor.visit_pat(&**subpattern),
- }
+ walk_list!(visitor, visit_pat, optional_subpattern);
}
- PatLit(ref expression) => visitor.visit_expr(&**expression),
+ PatLit(ref expression) => visitor.visit_expr(expression),
PatRange(ref lower_bound, ref upper_bound) => {
- visitor.visit_expr(&**lower_bound);
- visitor.visit_expr(&**upper_bound)
+ visitor.visit_expr(lower_bound);
+ visitor.visit_expr(upper_bound)
}
PatWild(_) => (),
- PatVec(ref prepattern, ref slice_pattern, ref postpatterns) => {
- for prepattern in prepattern {
- visitor.visit_pat(&**prepattern)
- }
- if let Some(ref slice_pattern) = *slice_pattern {
- visitor.visit_pat(&**slice_pattern)
- }
- for postpattern in postpatterns {
- visitor.visit_pat(&**postpattern)
- }
+ PatVec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+ walk_list!(visitor, visit_pat, prepatterns);
+ walk_list!(visitor, visit_pat, slice_pattern);
+ walk_list!(visitor, visit_pat, postpatterns);
}
}
}
-pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V,
- foreign_item: &'v ForeignItem) {
- visitor.visit_ident(foreign_item.span, foreign_item.ident);
+pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem) {
+ visitor.visit_name(foreign_item.span, foreign_item.name);
match foreign_item.node {
ForeignItemFn(ref function_declaration, ref generics) => {
- walk_fn_decl(visitor, &**function_declaration);
+ walk_fn_decl(visitor, function_declaration);
visitor.visit_generics(generics)
}
- ForeignItemStatic(ref typ, _) => visitor.visit_ty(&**typ),
+ ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
}
- for attr in &foreign_item.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_list!(visitor, visit_attribute, &foreign_item.attrs);
}
-pub fn walk_ty_param_bounds_helper<'v, V: Visitor<'v>>(visitor: &mut V,
- bounds: &'v OwnedSlice<TyParamBound>) {
- for bound in bounds.iter() {
- visitor.visit_ty_param_bound(bound)
- }
-}
-
-pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V,
- bound: &'v TyParamBound) {
+pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) {
match *bound {
TraitTyParamBound(ref typ, ref modifier) => {
visitor.visit_poly_trait_ref(typ, modifier);
}
RegionTyParamBound(ref lifetime) => {
- visitor.visit_lifetime_bound(lifetime);
+ visitor.visit_lifetime(lifetime);
}
}
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
- for param in generics.ty_params.iter() {
- visitor.visit_ident(param.span, param.ident);
- walk_ty_param_bounds_helper(visitor, ¶m.bounds);
- walk_ty_opt(visitor, ¶m.default);
+ for param in &generics.ty_params {
+ visitor.visit_name(param.span, param.name);
+ walk_list!(visitor, visit_ty_param_bound, ¶m.bounds);
+ walk_list!(visitor, visit_ty, ¶m.default);
}
- walk_lifetime_decls_helper(visitor, &generics.lifetimes);
+ walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
for predicate in &generics.where_clause.predicates {
match predicate {
- &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate{ref bounded_ty,
+ &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
ref bounds,
+ ref bound_lifetimes,
..}) => {
- visitor.visit_ty(&**bounded_ty);
- walk_ty_param_bounds_helper(visitor, bounds);
+ visitor.visit_ty(bounded_ty);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
}
- &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate{ref lifetime,
+ &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
ref bounds,
..}) => {
- visitor.visit_lifetime_ref(lifetime);
-
- for bound in bounds {
- visitor.visit_lifetime_ref(bound);
- }
+ visitor.visit_lifetime(lifetime);
+ walk_list!(visitor, visit_lifetime, bounds);
}
- &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate{id,
+ &WherePredicate::EqPredicate(WhereEqPredicate{id,
ref path,
ref ty,
..}) => {
visitor.visit_path(path, id);
- visitor.visit_ty(&**ty);
+ visitor.visit_ty(ty);
}
}
}
pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) {
if let Return(ref output_ty) = *ret_ty {
- visitor.visit_ty(&**output_ty)
+ visitor.visit_ty(output_ty)
}
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
for argument in &function_declaration.inputs {
- visitor.visit_pat(&*argument.pat);
- visitor.visit_ty(&*argument.ty)
+ visitor.visit_pat(&argument.pat);
+ visitor.visit_ty(&argument.ty)
}
walk_fn_ret_ty(visitor, &function_declaration.output)
}
-pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V,
- function_kind: FnKind<'v>) {
+pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
+ for argument in &function_declaration.inputs {
+ visitor.visit_ty(&argument.ty)
+ }
+ walk_fn_ret_ty(visitor, &function_declaration.output)
+}
+
+pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
match function_kind {
FnKind::ItemFn(_, generics, _, _, _, _) => {
visitor.visit_generics(generics);
visitor.visit_generics(&sig.generics);
visitor.visit_explicit_self(&sig.explicit_self);
}
- FnKind::Closure(..) => {}
+ FnKind::Closure => {}
}
}
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
- visitor.visit_ident(trait_item.span, trait_item.ident);
- for attr in &trait_item.attrs {
- visitor.visit_attribute(attr);
- }
+ visitor.visit_name(trait_item.span, trait_item.name);
+ walk_list!(visitor, visit_attribute, &trait_item.attrs);
match trait_item.node {
ConstTraitItem(ref ty, ref default) => {
visitor.visit_ty(ty);
- if let Some(ref expr) = *default {
- visitor.visit_expr(expr);
- }
+ walk_list!(visitor, visit_expr, default);
}
MethodTraitItem(ref sig, None) => {
visitor.visit_explicit_self(&sig.explicit_self);
walk_fn_decl(visitor, &sig.decl);
}
MethodTraitItem(ref sig, Some(ref body)) => {
- visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None), &sig.decl,
- body, trait_item.span, trait_item.id);
+ visitor.visit_fn(FnKind::Method(trait_item.name, sig, None),
+ &sig.decl,
+ body,
+ trait_item.span,
+ trait_item.id);
}
TypeTraitItem(ref bounds, ref default) => {
- walk_ty_param_bounds_helper(visitor, bounds);
- walk_ty_opt(visitor, default);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_ty, default);
}
}
}
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
- visitor.visit_ident(impl_item.span, impl_item.ident);
- for attr in &impl_item.attrs {
- visitor.visit_attribute(attr);
- }
+ visitor.visit_name(impl_item.span, impl_item.name);
+ walk_list!(visitor, visit_attribute, &impl_item.attrs);
match impl_item.node {
ConstImplItem(ref ty, ref expr) => {
visitor.visit_ty(ty);
visitor.visit_expr(expr);
}
MethodImplItem(ref sig, ref body) => {
- visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl,
- body, impl_item.span, impl_item.id);
+ visitor.visit_fn(FnKind::Method(impl_item.name, sig, Some(impl_item.vis)),
+ &sig.decl,
+ body,
+ impl_item.span,
+ impl_item.id);
}
TypeImplItem(ref ty) => {
visitor.visit_ty(ty);
}
}
-pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V,
- struct_definition: &'v StructDef) {
- for field in &struct_definition.fields {
- visitor.visit_struct_field(field)
- }
+pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: &'v VariantData) {
+ walk_list!(visitor, visit_struct_field, struct_definition.fields());
}
-pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V,
- struct_field: &'v StructField) {
- if let NamedField(name, _) = struct_field.node.kind {
- visitor.visit_ident(struct_field.span, name);
- }
-
- visitor.visit_ty(&*struct_field.node.ty);
-
- for attr in &struct_field.node.attrs {
- visitor.visit_attribute(attr);
- }
+pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) {
+ walk_opt_name(visitor, struct_field.span, struct_field.node.name());
+ visitor.visit_ty(&struct_field.node.ty);
+ walk_list!(visitor, visit_attribute, &struct_field.node.attrs);
}
pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) {
- for statement in &block.stmts {
- visitor.visit_stmt(&**statement)
- }
- walk_expr_opt(visitor, &block.expr)
+ walk_list!(visitor, visit_stmt, &block.stmts);
+ walk_list!(visitor, visit_expr, &block.expr);
}
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
match statement.node {
- StmtDecl(ref declaration, _) => visitor.visit_decl(&**declaration),
+ StmtDecl(ref declaration, _) => visitor.visit_decl(declaration),
StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => {
- visitor.visit_expr(&**expression)
+ visitor.visit_expr(expression)
}
}
}
pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
match declaration.node {
- DeclLocal(ref local) => visitor.visit_local(&**local),
- DeclItem(ref item) => visitor.visit_item(&**item),
- }
-}
-
-pub fn walk_expr_opt<'v, V: Visitor<'v>>(visitor: &mut V,
- optional_expression: &'v Option<P<Expr>>) {
- match *optional_expression {
- None => {}
- Some(ref expression) => visitor.visit_expr(&**expression),
- }
-}
-
-pub fn walk_exprs<'v, V: Visitor<'v>>(visitor: &mut V, expressions: &'v [P<Expr>]) {
- for expression in expressions {
- visitor.visit_expr(&**expression)
+ DeclLocal(ref local) => visitor.visit_local(local),
+ DeclItem(ref item) => visitor.visit_item(item),
}
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
match expression.node {
- ExprBox(ref place, ref subexpression) => {
- place.as_ref().map(|e|visitor.visit_expr(&**e));
- visitor.visit_expr(&**subexpression)
+ ExprBox(ref subexpression) => {
+ visitor.visit_expr(subexpression)
}
ExprVec(ref subexpressions) => {
- walk_exprs(visitor, subexpressions)
+ walk_list!(visitor, visit_expr, subexpressions);
}
ExprRepeat(ref element, ref count) => {
- visitor.visit_expr(&**element);
- visitor.visit_expr(&**count)
+ visitor.visit_expr(element);
+ visitor.visit_expr(count)
}
ExprStruct(ref path, ref fields, ref optional_base) => {
visitor.visit_path(path, expression.id);
for field in fields {
- visitor.visit_expr(&*field.expr)
+ visitor.visit_name(field.name.span, field.name.node);
+ visitor.visit_expr(&field.expr)
}
- walk_expr_opt(visitor, optional_base)
+ walk_list!(visitor, visit_expr, optional_base);
}
ExprTup(ref subexpressions) => {
- for subexpression in subexpressions {
- visitor.visit_expr(&**subexpression)
- }
+ walk_list!(visitor, visit_expr, subexpressions);
}
ExprCall(ref callee_expression, ref arguments) => {
- for argument in arguments {
- visitor.visit_expr(&**argument)
- }
- visitor.visit_expr(&**callee_expression)
+ walk_list!(visitor, visit_expr, arguments);
+ visitor.visit_expr(callee_expression)
}
- ExprMethodCall(_, ref types, ref arguments) => {
- walk_exprs(visitor, arguments);
- for typ in types {
- visitor.visit_ty(&**typ)
- }
+ ExprMethodCall(ref name, ref types, ref arguments) => {
+ visitor.visit_name(name.span, name.node);
+ walk_list!(visitor, visit_expr, arguments);
+ walk_list!(visitor, visit_ty, types);
}
ExprBinary(_, ref left_expression, ref right_expression) => {
- visitor.visit_expr(&**left_expression);
- visitor.visit_expr(&**right_expression)
+ visitor.visit_expr(left_expression);
+ visitor.visit_expr(right_expression)
}
ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => {
- visitor.visit_expr(&**subexpression)
+ visitor.visit_expr(subexpression)
}
ExprLit(_) => {}
ExprCast(ref subexpression, ref typ) => {
- visitor.visit_expr(&**subexpression);
- visitor.visit_ty(&**typ)
+ visitor.visit_expr(subexpression);
+ visitor.visit_ty(typ)
}
ExprIf(ref head_expression, ref if_block, ref optional_else) => {
- visitor.visit_expr(&**head_expression);
- visitor.visit_block(&**if_block);
- walk_expr_opt(visitor, optional_else)
+ visitor.visit_expr(head_expression);
+ visitor.visit_block(if_block);
+ walk_list!(visitor, visit_expr, optional_else);
}
- ExprWhile(ref subexpression, ref block, _) => {
- visitor.visit_expr(&**subexpression);
- visitor.visit_block(&**block)
+ ExprWhile(ref subexpression, ref block, opt_ident) => {
+ visitor.visit_expr(subexpression);
+ visitor.visit_block(block);
+ walk_opt_ident(visitor, expression.span, opt_ident)
+ }
+ ExprLoop(ref block, opt_ident) => {
+ visitor.visit_block(block);
+ walk_opt_ident(visitor, expression.span, opt_ident)
}
- ExprLoop(ref block, _) => visitor.visit_block(&**block),
ExprMatch(ref subexpression, ref arms, _) => {
- visitor.visit_expr(&**subexpression);
- for arm in arms {
- visitor.visit_arm(arm)
- }
+ visitor.visit_expr(subexpression);
+ walk_list!(visitor, visit_arm, arms);
}
ExprClosure(_, ref function_declaration, ref body) => {
visitor.visit_fn(FnKind::Closure,
- &**function_declaration,
- &**body,
+ function_declaration,
+ body,
expression.span,
expression.id)
}
- ExprBlock(ref block) => visitor.visit_block(&**block),
+ ExprBlock(ref block) => visitor.visit_block(block),
ExprAssign(ref left_hand_expression, ref right_hand_expression) => {
- visitor.visit_expr(&**right_hand_expression);
- visitor.visit_expr(&**left_hand_expression)
+ visitor.visit_expr(right_hand_expression);
+ visitor.visit_expr(left_hand_expression)
}
ExprAssignOp(_, ref left_expression, ref right_expression) => {
- visitor.visit_expr(&**right_expression);
- visitor.visit_expr(&**left_expression)
+ visitor.visit_expr(right_expression);
+ visitor.visit_expr(left_expression)
}
- ExprField(ref subexpression, _) => {
- visitor.visit_expr(&**subexpression);
+ ExprField(ref subexpression, ref name) => {
+ visitor.visit_expr(subexpression);
+ visitor.visit_name(name.span, name.node);
}
ExprTupField(ref subexpression, _) => {
- visitor.visit_expr(&**subexpression);
+ visitor.visit_expr(subexpression);
}
ExprIndex(ref main_expression, ref index_expression) => {
- visitor.visit_expr(&**main_expression);
- visitor.visit_expr(&**index_expression)
+ visitor.visit_expr(main_expression);
+ visitor.visit_expr(index_expression)
}
ExprRange(ref start, ref end) => {
- walk_expr_opt(visitor, start);
- walk_expr_opt(visitor, end)
+ walk_list!(visitor, visit_expr, start);
+ walk_list!(visitor, visit_expr, end);
}
ExprPath(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself {
}
visitor.visit_path(path, expression.id)
}
- ExprBreak(_) | ExprAgain(_) => {}
- ExprRet(ref optional_expression) => {
- walk_expr_opt(visitor, optional_expression)
+ ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => {
+ for sp_ident in opt_sp_ident {
+ visitor.visit_ident(sp_ident.span, sp_ident.node);
+ }
}
- ExprParen(ref subexpression) => {
- visitor.visit_expr(&**subexpression)
+ ExprRet(ref optional_expression) => {
+ walk_list!(visitor, visit_expr, optional_expression);
}
ExprInlineAsm(ref ia) => {
- for input in &ia.inputs {
- let (_, ref input) = *input;
- visitor.visit_expr(&**input)
+ for &(_, ref input) in &ia.inputs {
+ visitor.visit_expr(&input)
}
- for output in &ia.outputs {
- let (_, ref output, _) = *output;
- visitor.visit_expr(&**output)
+ for &(_, ref output, _) in &ia.outputs {
+ visitor.visit_expr(&output)
}
}
}
}
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
- for pattern in &arm.pats {
- visitor.visit_pat(&**pattern)
- }
- walk_expr_opt(visitor, &arm.guard);
- visitor.visit_expr(&*arm.body);
- for attr in &arm.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_list!(visitor, visit_pat, &arm.pats);
+ walk_list!(visitor, visit_expr, &arm.guard);
+ visitor.visit_expr(&arm.body);
+ walk_list!(visitor, visit_attribute, &arm.attrs);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::def;
+use middle::ty;
+use lint::{LateContext, LintContext, LintArray};
+use lint::{LintPass, LateLintPass};
+
+use syntax::ast;
+use syntax::attr::{self, AttrMetaMethods};
+use syntax::codemap::Span;
+
+use rustc_front::hir;
+use rustc_front::visit::FnKind;
+
+#[derive(PartialEq)]
+pub enum MethodLateContext {
+ TraitDefaultImpl,
+ TraitImpl,
+ PlainImpl
+}
+
+pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
+ let def_id = cx.tcx.map.local_def_id(id);
+ match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
+ None => cx.sess().span_bug(span, "missing method descriptor?!"),
+ Some(item) => match item.container() {
+ ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
+ ty::ImplContainer(cid) => {
+ match cx.tcx.impl_trait_ref(cid) {
+ Some(_) => MethodLateContext::TraitImpl,
+ None => MethodLateContext::PlainImpl
+ }
+ }
+ }
+ }
+}
+
+declare_lint! {
+ pub NON_CAMEL_CASE_TYPES,
+ Warn,
+ "types, variants, traits and type parameters should have camel case names"
+}
+
+#[derive(Copy, Clone)]
+pub struct NonCamelCaseTypes;
+
+impl NonCamelCaseTypes {
+ fn check_case(&self, cx: &LateContext, sort: &str, name: ast::Name, span: Span) {
+ fn is_camel_case(name: ast::Name) -> bool {
+ let name = name.as_str();
+ if name.is_empty() {
+ return true;
+ }
+ let name = name.trim_matches('_');
+
+ // start with a non-lowercase letter rather than non-uppercase
+ // ones (some scripts don't have a concept of upper/lowercase)
+ !name.is_empty() && !name.char_at(0).is_lowercase() && !name.contains('_')
+ }
+
+ fn to_camel_case(s: &str) -> String {
+ s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)|
+ if i == 0 {
+ c.to_uppercase().collect::<String>()
+ } else {
+ c.to_lowercase().collect()
+ }
+ )).collect::<Vec<_>>().concat()
+ }
+
+ let s = name.as_str();
+
+ if !is_camel_case(name) {
+ let c = to_camel_case(&s);
+ let m = if c.is_empty() {
+ format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s)
+ } else {
+ format!("{} `{}` should have a camel case name such as `{}`", sort, s, c)
+ };
+ cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]);
+ }
+ }
+}
+
+impl LintPass for NonCamelCaseTypes {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(NON_CAMEL_CASE_TYPES)
+ }
+}
+
+impl LateLintPass for NonCamelCaseTypes {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ let extern_repr_count = it.attrs.iter().filter(|attr| {
+ attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
+ .any(|r| r == &attr::ReprExtern)
+ }).count();
+ let has_extern_repr = extern_repr_count > 0;
+
+ if has_extern_repr {
+ return;
+ }
+
+ match it.node {
+ hir::ItemTy(..) | hir::ItemStruct(..) => {
+ self.check_case(cx, "type", it.name, it.span)
+ }
+ hir::ItemTrait(..) => {
+ self.check_case(cx, "trait", it.name, it.span)
+ }
+ hir::ItemEnum(ref enum_definition, _) => {
+ if has_extern_repr {
+ return;
+ }
+ self.check_case(cx, "type", it.name, it.span);
+ for variant in &enum_definition.variants {
+ self.check_case(cx, "variant", variant.node.name, variant.span);
+ }
+ }
+ _ => ()
+ }
+ }
+
+ fn check_generics(&mut self, cx: &LateContext, it: &hir::Generics) {
+ for gen in it.ty_params.iter() {
+ self.check_case(cx, "type parameter", gen.name, gen.span);
+ }
+ }
+}
+
+declare_lint! {
+ pub NON_SNAKE_CASE,
+ Warn,
+ "methods, functions, lifetime parameters and modules should have snake case names"
+}
+
+#[derive(Copy, Clone)]
+pub struct NonSnakeCase;
+
+impl NonSnakeCase {
+ fn to_snake_case(mut str: &str) -> String {
+ let mut words = vec![];
+ // Preserve leading underscores
+ str = str.trim_left_matches(|c: char| {
+ if c == '_' {
+ words.push(String::new());
+ true
+ } else {
+ false
+ }
+ });
+ for s in str.split('_') {
+ let mut last_upper = false;
+ let mut buf = String::new();
+ if s.is_empty() {
+ continue;
+ }
+ for ch in s.chars() {
+ if !buf.is_empty() && buf != "'"
+ && ch.is_uppercase()
+ && !last_upper {
+ words.push(buf);
+ buf = String::new();
+ }
+ last_upper = ch.is_uppercase();
+ buf.extend(ch.to_lowercase());
+ }
+ words.push(buf);
+ }
+ words.join("_")
+ }
+
+ fn check_snake_case(&self, cx: &LateContext, sort: &str, name: &str, span: Option<Span>) {
+ fn is_snake_case(ident: &str) -> bool {
+ if ident.is_empty() {
+ return true;
+ }
+ let ident = ident.trim_left_matches('\'');
+ let ident = ident.trim_matches('_');
+
+ let mut allow_underscore = true;
+ ident.chars().all(|c| {
+ allow_underscore = match c {
+ '_' if !allow_underscore => return false,
+ '_' => false,
+ // It would be more obvious to use `c.is_lowercase()`,
+ // but some characters do not have a lowercase form
+ c if !c.is_uppercase() => true,
+ _ => return false,
+ };
+ true
+ })
+ }
+
+ if !is_snake_case(name) {
+ let sc = NonSnakeCase::to_snake_case(name);
+ let msg = if sc != name {
+ format!("{} `{}` should have a snake case name such as `{}`",
+ sort, name, sc)
+ } else {
+ format!("{} `{}` should have a snake case name",
+ sort, name)
+ };
+ match span {
+ Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
+ None => cx.lint(NON_SNAKE_CASE, &msg),
+ }
+ }
+ }
+}
+
+impl LintPass for NonSnakeCase {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(NON_SNAKE_CASE)
+ }
+}
+
+impl LateLintPass for NonSnakeCase {
+ fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
+ let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name"))
+ .and_then(|at| at.value_str().map(|s| (at, s)));
+ if let Some(ref name) = cx.tcx.sess.opts.crate_name {
+ self.check_snake_case(cx, "crate", name, None);
+ } else if let Some((attr, ref name)) = attr_crate_name {
+ self.check_snake_case(cx, "crate", name, Some(attr.span));
+ }
+ }
+
+ fn check_fn(&mut self, cx: &LateContext,
+ fk: FnKind, _: &hir::FnDecl,
+ _: &hir::Block, span: Span, id: ast::NodeId) {
+ match fk {
+ FnKind::Method(name, _, _) => match method_context(cx, id, span) {
+ MethodLateContext::PlainImpl => {
+ self.check_snake_case(cx, "method", &name.as_str(), Some(span))
+ },
+ MethodLateContext::TraitDefaultImpl => {
+ self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
+ },
+ _ => (),
+ },
+ FnKind::ItemFn(name, _, _, _, _, _) => {
+ self.check_snake_case(cx, "function", &name.as_str(), Some(span))
+ },
+ _ => (),
+ }
+ }
+
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ if let hir::ItemMod(_) = it.node {
+ self.check_snake_case(cx, "module", &it.name.as_str(), Some(it.span));
+ }
+ }
+
+ fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
+ if let hir::MethodTraitItem(_, None) = trait_item.node {
+ self.check_snake_case(cx, "trait method", &trait_item.name.as_str(),
+ Some(trait_item.span));
+ }
+ }
+
+ fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
+ self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(),
+ Some(t.lifetime.span));
+ }
+
+ fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
+ if let &hir::PatIdent(_, ref path1, _) = &p.node {
+ let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
+ if let Some(def::DefLocal(..)) = def {
+ self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span));
+ }
+ }
+ }
+
+ fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData,
+ _: ast::Name, _: &hir::Generics, _: ast::NodeId) {
+ for sf in s.fields() {
+ if let hir::StructField_ { kind: hir::NamedField(name, _), .. } = sf.node {
+ self.check_snake_case(cx, "structure field", &name.as_str(),
+ Some(sf.span));
+ }
+ }
+ }
+}
+
+declare_lint! {
+ pub NON_UPPER_CASE_GLOBALS,
+ Warn,
+ "static constants should have uppercase identifiers"
+}
+
+#[derive(Copy, Clone)]
+pub struct NonUpperCaseGlobals;
+
+impl NonUpperCaseGlobals {
+ fn check_upper_case(cx: &LateContext, sort: &str, name: ast::Name, span: Span) {
+ let s = name.as_str();
+
+ if s.chars().any(|c| c.is_lowercase()) {
+ let uc = NonSnakeCase::to_snake_case(&s).to_uppercase();
+ if uc != &s[..] {
+ cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
+ &format!("{} `{}` should have an upper case name such as `{}`",
+ sort, s, uc));
+ } else {
+ cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
+ &format!("{} `{}` should have an upper case name",
+ sort, s));
+ }
+ }
+ }
+}
+
+impl LintPass for NonUpperCaseGlobals {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(NON_UPPER_CASE_GLOBALS)
+ }
+}
+
+impl LateLintPass for NonUpperCaseGlobals {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ match it.node {
+ // only check static constants
+ hir::ItemStatic(_, hir::MutImmutable, _) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "static constant", it.name, it.span);
+ }
+ hir::ItemConst(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "constant", it.name, it.span);
+ }
+ _ => {}
+ }
+ }
+
+ fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
+ match ti.node {
+ hir::ConstTraitItem(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+ ti.name, ti.span);
+ }
+ _ => {}
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
+ match ii.node {
+ hir::ConstImplItem(..) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
+ ii.name, ii.span);
+ }
+ _ => {}
+ }
+ }
+
+ fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
+ // Lint for constants that look like binding identifiers (#7526)
+ match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
+ (&hir::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
+ NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
+ path1.node.name, p.span);
+ }
+ _ => {}
+ }
+ }
+}
//! Use the former for unit-like structs and the latter for structs with
//! a `pub fn new()`.
-use metadata::{csearch, decoder};
-use middle::{cfg, def, infer, pat_util, stability, traits};
+use metadata::decoder;
+use middle::{cfg, def, infer, stability, traits};
use middle::def_id::DefId;
use middle::subst::Substs;
use middle::ty::{self, Ty};
use middle::ty::adjustment;
-use middle::const_eval::{eval_const_expr_partial, ConstVal};
-use middle::const_eval::EvalHint::ExprTypeChecked;
use rustc::front::map as hir_map;
-use util::nodemap::{FnvHashMap, FnvHashSet, NodeSet};
-use lint::{Level, Context, LintPass, LintArray, Lint};
+use util::nodemap::{NodeSet};
+use lint::{Level, LateContext, LintContext, LintArray, Lint};
+use lint::{LintPass, LateLintPass};
use std::collections::HashSet;
-use std::collections::hash_map::Entry::{Occupied, Vacant};
-use std::{cmp, slice};
-use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
-use syntax::{abi, ast};
-use syntax::attr as syntax_attr;
+use syntax::{ast};
+use syntax::attr::{self, AttrMetaMethods};
use syntax::codemap::{self, Span};
-use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType};
-use rustc_front::hir::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
-use syntax::ptr::P;
use rustc_front::hir;
+use rustc_front::visit::{self, FnKind, Visitor};
-use rustc_front::attr::{self, AttrMetaMethods};
-use rustc_front::visit::{self, FnKind, Visitor};
-use rustc_front::lowering::unlower_attribute;
-
-use rustc_front::util::is_shift_binop;
-
-// hardwired lints from librustc
-pub use lint::builtin::*;
-
-declare_lint! {
- WHILE_TRUE,
- Warn,
- "suggest using `loop { }` instead of `while true { }`"
-}
-
-#[derive(Copy, Clone)]
-pub struct WhileTrue;
-
-impl LintPass for WhileTrue {
- fn get_lints(&self) -> LintArray {
- lint_array!(WHILE_TRUE)
- }
-
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
- if let hir::ExprWhile(ref cond, _, _) = e.node {
- if let hir::ExprLit(ref lit) = cond.node {
- if let hir::LitBool(true) = lit.node {
- cx.span_lint(WHILE_TRUE, e.span,
- "denote infinite loops with loop { ... }");
- }
- }
- }
- }
-}
-
-declare_lint! {
- UNUSED_COMPARISONS,
- Warn,
- "comparisons made useless by limits of the types involved"
-}
-
-declare_lint! {
- OVERFLOWING_LITERALS,
- Warn,
- "literal out of range for its type"
-}
-
-declare_lint! {
- EXCEEDING_BITSHIFTS,
- Deny,
- "shift exceeds the type's number of bits"
-}
-
-#[derive(Copy, Clone)]
-pub struct TypeLimits {
- /// Id of the last visited negated expression
- negated_expr_id: ast::NodeId,
-}
-
-impl TypeLimits {
- pub fn new() -> TypeLimits {
- TypeLimits {
- negated_expr_id: !0,
- }
- }
-}
-
-impl LintPass for TypeLimits {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS)
- }
-
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
- match e.node {
- hir::ExprUnary(hir::UnNeg, ref expr) => {
- match expr.node {
- hir::ExprLit(ref lit) => {
- match lit.node {
- hir::LitInt(_, hir::UnsignedIntLit(_)) => {
- check_unsigned_negation_feature(cx, e.span);
- },
- hir::LitInt(_, hir::UnsuffixedIntLit(_)) => {
- if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
- check_unsigned_negation_feature(cx, e.span);
- }
- },
- _ => ()
- }
- },
- _ => {
- let t = cx.tcx.node_id_to_type(expr.id);
- match t.sty {
- ty::TyUint(_) => {
- check_unsigned_negation_feature(cx, e.span);
- },
- _ => ()
- }
- }
- };
- // propagate negation, if the negation itself isn't negated
- if self.negated_expr_id != e.id {
- self.negated_expr_id = expr.id;
- }
- },
- hir::ExprParen(ref expr) if self.negated_expr_id == e.id => {
- self.negated_expr_id = expr.id;
- },
- hir::ExprBinary(binop, ref l, ref r) => {
- if is_comparison(binop) && !check_limits(cx.tcx, binop, &**l, &**r) {
- cx.span_lint(UNUSED_COMPARISONS, e.span,
- "comparison is useless due to type limits");
- }
-
- if is_shift_binop(binop.node) {
- let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
- ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
- ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
- _ => None
- };
-
- if let Some(bits) = opt_ty_bits {
- let exceeding = if let hir::ExprLit(ref lit) = r.node {
- if let hir::LitInt(shift, _) = lit.node { shift >= bits }
- else { false }
- } else {
- match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked) {
- Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
- Ok(ConstVal::Uint(shift)) => { shift >= bits },
- _ => { false }
- }
- };
- if exceeding {
- cx.span_lint(EXCEEDING_BITSHIFTS, e.span,
- "bitshift exceeds the type's number of bits");
- }
- };
- }
- },
- hir::ExprLit(ref lit) => {
- match cx.tcx.node_id_to_type(e.id).sty {
- ty::TyInt(t) => {
- match lit.node {
- hir::LitInt(v, hir::SignedIntLit(_, hir::Plus)) |
- hir::LitInt(v, hir::UnsuffixedIntLit(hir::Plus)) => {
- let int_type = if let hir::TyIs = t {
- cx.sess().target.int_type
- } else {
- t
- };
- let (_, max) = int_ty_range(int_type);
- let negative = self.negated_expr_id == e.id;
-
- // Detect literal value out of range [min, max] inclusive
- // avoiding use of -min to prevent overflow/panic
- if (negative && v > max as u64 + 1) ||
- (!negative && v > max as u64) {
- cx.span_lint(OVERFLOWING_LITERALS, e.span,
- &*format!("literal out of range for {:?}", t));
- return;
- }
- }
- _ => panic!()
- };
- },
- ty::TyUint(t) => {
- let uint_type = if let hir::TyUs = t {
- cx.sess().target.uint_type
- } else {
- t
- };
- let (min, max) = uint_ty_range(uint_type);
- let lit_val: u64 = match lit.node {
- hir::LitByte(_v) => return, // _v is u8, within range by definition
- hir::LitInt(v, _) => v,
- _ => panic!()
- };
- if lit_val < min || lit_val > max {
- cx.span_lint(OVERFLOWING_LITERALS, e.span,
- &*format!("literal out of range for {:?}", t));
- }
- },
- ty::TyFloat(t) => {
- let (min, max) = float_ty_range(t);
- let lit_val: f64 = match lit.node {
- hir::LitFloat(ref v, _) |
- hir::LitFloatUnsuffixed(ref v) => {
- match v.parse() {
- Ok(f) => f,
- Err(_) => return
- }
- }
- _ => panic!()
- };
- if lit_val < min || lit_val > max {
- cx.span_lint(OVERFLOWING_LITERALS, e.span,
- &*format!("literal out of range for {:?}", t));
- }
- },
- _ => ()
- };
- },
- _ => ()
- };
-
- fn is_valid<T:cmp::PartialOrd>(binop: hir::BinOp, v: T,
- min: T, max: T) -> bool {
- match binop.node {
- hir::BiLt => v > min && v <= max,
- hir::BiLe => v >= min && v < max,
- hir::BiGt => v >= min && v < max,
- hir::BiGe => v > min && v <= max,
- hir::BiEq | hir::BiNe => v >= min && v <= max,
- _ => panic!()
- }
- }
-
- fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
- codemap::respan(binop.span, match binop.node {
- hir::BiLt => hir::BiGt,
- hir::BiLe => hir::BiGe,
- hir::BiGt => hir::BiLt,
- hir::BiGe => hir::BiLe,
- _ => return binop
- })
- }
-
- // for isize & usize, be conservative with the warnings, so that the
- // warnings are consistent between 32- and 64-bit platforms
- fn int_ty_range(int_ty: hir::IntTy) -> (i64, i64) {
- match int_ty {
- hir::TyIs => (i64::MIN, i64::MAX),
- hir::TyI8 => (i8::MIN as i64, i8::MAX as i64),
- hir::TyI16 => (i16::MIN as i64, i16::MAX as i64),
- hir::TyI32 => (i32::MIN as i64, i32::MAX as i64),
- hir::TyI64 => (i64::MIN, i64::MAX)
- }
- }
-
- fn uint_ty_range(uint_ty: hir::UintTy) -> (u64, u64) {
- match uint_ty {
- hir::TyUs => (u64::MIN, u64::MAX),
- hir::TyU8 => (u8::MIN as u64, u8::MAX as u64),
- hir::TyU16 => (u16::MIN as u64, u16::MAX as u64),
- hir::TyU32 => (u32::MIN as u64, u32::MAX as u64),
- hir::TyU64 => (u64::MIN, u64::MAX)
- }
- }
-
- fn float_ty_range(float_ty: hir::FloatTy) -> (f64, f64) {
- match float_ty {
- hir::TyF32 => (f32::MIN as f64, f32::MAX as f64),
- hir::TyF64 => (f64::MIN, f64::MAX)
- }
- }
-
- fn int_ty_bits(int_ty: hir::IntTy, target_int_ty: hir::IntTy) -> u64 {
- match int_ty {
- hir::TyIs => int_ty_bits(target_int_ty, target_int_ty),
- hir::TyI8 => i8::BITS as u64,
- hir::TyI16 => i16::BITS as u64,
- hir::TyI32 => i32::BITS as u64,
- hir::TyI64 => i64::BITS as u64
- }
- }
-
- fn uint_ty_bits(uint_ty: hir::UintTy, target_uint_ty: hir::UintTy) -> u64 {
- match uint_ty {
- hir::TyUs => uint_ty_bits(target_uint_ty, target_uint_ty),
- hir::TyU8 => u8::BITS as u64,
- hir::TyU16 => u16::BITS as u64,
- hir::TyU32 => u32::BITS as u64,
- hir::TyU64 => u64::BITS as u64
- }
- }
-
- fn check_limits(tcx: &ty::ctxt, binop: hir::BinOp,
- l: &hir::Expr, r: &hir::Expr) -> bool {
- let (lit, expr, swap) = match (&l.node, &r.node) {
- (&hir::ExprLit(_), _) => (l, r, true),
- (_, &hir::ExprLit(_)) => (r, l, false),
- _ => return true
- };
- // Normalize the binop so that the literal is always on the RHS in
- // the comparison
- let norm_binop = if swap {
- rev_binop(binop)
- } else {
- binop
- };
- match tcx.node_id_to_type(expr.id).sty {
- ty::TyInt(int_ty) => {
- let (min, max) = int_ty_range(int_ty);
- let lit_val: i64 = match lit.node {
- hir::ExprLit(ref li) => match li.node {
- hir::LitInt(v, hir::SignedIntLit(_, hir::Plus)) |
- hir::LitInt(v, hir::UnsuffixedIntLit(hir::Plus)) => v as i64,
- hir::LitInt(v, hir::SignedIntLit(_, hir::Minus)) |
- hir::LitInt(v, hir::UnsuffixedIntLit(hir::Minus)) => -(v as i64),
- _ => return true
- },
- _ => panic!()
- };
- is_valid(norm_binop, lit_val, min, max)
- }
- ty::TyUint(uint_ty) => {
- let (min, max): (u64, u64) = uint_ty_range(uint_ty);
- let lit_val: u64 = match lit.node {
- hir::ExprLit(ref li) => match li.node {
- hir::LitInt(v, _) => v,
- _ => return true
- },
- _ => panic!()
- };
- is_valid(norm_binop, lit_val, min, max)
- }
- _ => true
- }
- }
-
- fn is_comparison(binop: hir::BinOp) -> bool {
- match binop.node {
- hir::BiEq | hir::BiLt | hir::BiLe |
- hir::BiNe | hir::BiGe | hir::BiGt => true,
- _ => false
- }
- }
-
- fn check_unsigned_negation_feature(cx: &Context, span: Span) {
- if !cx.sess().features.borrow().negate_unsigned {
- // FIXME(#27141): change this to syntax::feature_gate::emit_feature_err…
- cx.sess().span_warn(span,
- "unary negation of unsigned integers will be feature gated in the future");
- // …and remove following two expressions.
- if option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some() { return; }
- cx.sess().fileline_help(span, "add #![feature(negate_unsigned)] to the \
- crate attributes to enable the gate in advance");
- }
- }
- }
-}
-
-declare_lint! {
- IMPROPER_CTYPES,
- Warn,
- "proper use of libc types in foreign modules"
-}
-
-struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
- cx: &'a Context<'a, 'tcx>
-}
-
-enum FfiResult {
- FfiSafe,
- FfiUnsafe(&'static str),
- FfiBadStruct(DefId, &'static str),
- FfiBadEnum(DefId, &'static str)
-}
-
-/// Check if this enum can be safely exported based on the
-/// "nullable pointer optimization". Currently restricted
-/// to function pointers and references, but could be
-/// expanded to cover NonZero raw pointers and newtypes.
-/// FIXME: This duplicates code in trans.
-fn is_repr_nullable_ptr<'tcx>(tcx: &ty::ctxt<'tcx>,
- def: ty::AdtDef<'tcx>,
- substs: &Substs<'tcx>)
- -> bool {
- if def.variants.len() == 2 {
- let data_idx;
-
- if def.variants[0].fields.is_empty() {
- data_idx = 1;
- } else if def.variants[1].fields.is_empty() {
- data_idx = 0;
- } else {
- return false;
- }
-
- if def.variants[data_idx].fields.len() == 1 {
- match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
- ty::TyBareFn(None, _) => { return true; }
- ty::TyRef(..) => { return true; }
- _ => { }
- }
- }
- }
- false
-}
-
-fn ast_ty_to_normalized<'tcx>(tcx: &ty::ctxt<'tcx>,
- id: ast::NodeId)
- -> Ty<'tcx> {
- let tty = match tcx.ast_ty_to_ty_cache.borrow().get(&id) {
- Some(&t) => t,
- None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
- };
- infer::normalize_associated_type(tcx, &tty)
-}
-
-impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
- /// Check if the given type is "ffi-safe" (has a stable, well-defined
- /// representation which can be exported to C code).
- fn check_type_for_ffi(&self,
- cache: &mut FnvHashSet<Ty<'tcx>>,
- ty: Ty<'tcx>)
- -> FfiResult {
- use self::FfiResult::*;
- let cx = &self.cx.tcx;
-
- // Protect against infinite recursion, for example
- // `struct S(*mut S);`.
- // FIXME: A recursion limit is necessary as well, for irregular
- // recusive types.
- if !cache.insert(ty) {
- return FfiSafe;
- }
-
- match ty.sty {
- ty::TyStruct(def, substs) => {
- if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
- return FfiUnsafe(
- "found struct without foreign-function-safe \
- representation annotation in foreign module, \
- consider adding a #[repr(C)] attribute to \
- the type");
- }
-
- // We can't completely trust repr(C) markings; make sure the
- // fields are actually safe.
- if def.struct_variant().fields.is_empty() {
- return FfiUnsafe(
- "found zero-size struct in foreign module, consider \
- adding a member to this struct");
- }
-
- for field in &def.struct_variant().fields {
- let field_ty = infer::normalize_associated_type(cx, &field.ty(cx, substs));
- let r = self.check_type_for_ffi(cache, field_ty);
- match r {
- FfiSafe => {}
- FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
- FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
- }
- }
- FfiSafe
- }
- ty::TyEnum(def, substs) => {
- if def.variants.is_empty() {
- // Empty enums are okay... although sort of useless.
- return FfiSafe
- }
-
- // Check for a repr() attribute to specify the size of the
- // discriminant.
- let repr_hints = cx.lookup_repr_hints(def.did);
- match &**repr_hints {
- [] => {
- // Special-case types like `Option<extern fn()>`.
- if !is_repr_nullable_ptr(cx, def, substs) {
- return FfiUnsafe(
- "found enum without foreign-function-safe \
- representation annotation in foreign module, \
- consider adding a #[repr(...)] attribute to \
- the type")
- }
- }
- [ref hint] => {
- if !hint.is_ffi_safe() {
- // FIXME: This shouldn't be reachable: we should check
- // this earlier.
- return FfiUnsafe(
- "enum has unexpected #[repr(...)] attribute")
- }
-
- // Enum with an explicitly sized discriminant; either
- // a C-style enum or a discriminated union.
-
- // The layout of enum variants is implicitly repr(C).
- // FIXME: Is that correct?
- }
- _ => {
- // FIXME: This shouldn't be reachable: we should check
- // this earlier.
- return FfiUnsafe(
- "enum has too many #[repr(...)] attributes");
- }
- }
-
- // Check the contained variants.
- for variant in &def.variants {
- for field in &variant.fields {
- let arg = infer::normalize_associated_type(cx, &field.ty(cx, substs));
- let r = self.check_type_for_ffi(cache, arg);
- match r {
- FfiSafe => {}
- FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
- FfiUnsafe(s) => { return FfiBadEnum(def.did, s); }
- }
- }
- }
- FfiSafe
- }
-
- ty::TyChar => {
- FfiUnsafe("found Rust type `char` in foreign module, while \
- `u32` or `libc::wchar_t` should be used")
- }
-
- // Primitive types with a stable representation.
- ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
- ty::TyFloat(..) => FfiSafe,
-
- ty::TyBox(..) => {
- FfiUnsafe("found Rust type Box<_> in foreign module, \
- consider using a raw pointer instead")
- }
-
- ty::TySlice(_) => {
- FfiUnsafe("found Rust slice type in foreign module, \
- consider using a raw pointer instead")
- }
-
- ty::TyTrait(..) => {
- FfiUnsafe("found Rust trait type in foreign module, \
- consider using a raw pointer instead")
- }
-
- ty::TyStr => {
- FfiUnsafe("found Rust type `str` in foreign module; \
- consider using a `*const libc::c_char`")
- }
-
- ty::TyTuple(_) => {
- FfiUnsafe("found Rust tuple type in foreign module; \
- consider using a struct instead`")
- }
-
- ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
- self.check_type_for_ffi(cache, m.ty)
- }
-
- ty::TyArray(ty, _) => {
- self.check_type_for_ffi(cache, ty)
- }
-
- ty::TyBareFn(None, bare_fn) => {
- match bare_fn.abi {
- abi::Rust |
- abi::RustIntrinsic |
- abi::PlatformIntrinsic |
- abi::RustCall => {
- return FfiUnsafe(
- "found function pointer with Rust calling \
- convention in foreign module; consider using an \
- `extern` function pointer")
- }
- _ => {}
- }
-
- let sig = cx.erase_late_bound_regions(&bare_fn.sig);
- match sig.output {
- ty::FnDiverging => {}
- ty::FnConverging(output) => {
- if !output.is_nil() {
- let r = self.check_type_for_ffi(cache, output);
- match r {
- FfiSafe => {}
- _ => { return r; }
- }
- }
- }
- }
- for arg in sig.inputs {
- let r = self.check_type_for_ffi(cache, arg);
- match r {
- FfiSafe => {}
- _ => { return r; }
- }
- }
- FfiSafe
- }
-
- ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
- ty::TyClosure(..) | ty::TyProjection(..) |
- ty::TyBareFn(Some(_), _) => {
- panic!("Unexpected type in foreign function")
- }
- }
- }
-
- fn check_def(&mut self, sp: Span, id: ast::NodeId) {
- let tty = ast_ty_to_normalized(self.cx.tcx, id);
-
- match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) {
- FfiResult::FfiSafe => {}
- FfiResult::FfiUnsafe(s) => {
- self.cx.span_lint(IMPROPER_CTYPES, sp, s);
- }
- FfiResult::FfiBadStruct(_, s) => {
- // FIXME: This diagnostic is difficult to read, and doesn't
- // point at the relevant field.
- self.cx.span_lint(IMPROPER_CTYPES, sp,
- &format!("found non-foreign-function-safe member in \
- struct marked #[repr(C)]: {}", s));
- }
- FfiResult::FfiBadEnum(_, s) => {
- // FIXME: This diagnostic is difficult to read, and doesn't
- // point at the relevant variant.
- self.cx.span_lint(IMPROPER_CTYPES, sp,
- &format!("found non-foreign-function-safe member in \
- enum: {}", s));
- }
- }
- }
-}
-
-impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
- fn visit_ty(&mut self, ty: &hir::Ty) {
- match ty.node {
- hir::TyPath(..) |
- hir::TyBareFn(..) => self.check_def(ty.span, ty.id),
- hir::TyVec(..) => {
- self.cx.span_lint(IMPROPER_CTYPES, ty.span,
- "found Rust slice type in foreign module, consider \
- using a raw pointer instead");
- }
- hir::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty),
- hir::TyTup(..) => {
- self.cx.span_lint(IMPROPER_CTYPES, ty.span,
- "found Rust tuple type in foreign module; \
- consider using a struct instead`")
- }
- _ => visit::walk_ty(self, ty)
- }
- }
-}
-
-#[derive(Copy, Clone)]
-pub struct ImproperCTypes;
-
-impl LintPass for ImproperCTypes {
- fn get_lints(&self) -> LintArray {
- lint_array!(IMPROPER_CTYPES)
- }
-
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
- fn check_ty(cx: &Context, ty: &hir::Ty) {
- let mut vis = ImproperCTypesVisitor { cx: cx };
- vis.visit_ty(ty);
- }
-
- fn check_foreign_fn(cx: &Context, decl: &hir::FnDecl) {
- for input in &decl.inputs {
- check_ty(cx, &*input.ty);
- }
- if let hir::Return(ref ret_ty) = decl.output {
- let tty = ast_ty_to_normalized(cx.tcx, ret_ty.id);
- if !tty.is_nil() {
- check_ty(cx, &ret_ty);
- }
- }
- }
-
- match it.node {
- hir::ItemForeignMod(ref nmod)
- if nmod.abi != abi::RustIntrinsic &&
- nmod.abi != abi::PlatformIntrinsic => {
- for ni in &nmod.items {
- match ni.node {
- hir::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &**decl),
- hir::ForeignItemStatic(ref t, _) => check_ty(cx, &**t)
- }
- }
- }
- _ => (),
- }
- }
-}
-
-declare_lint! {
- BOX_POINTERS,
- Allow,
- "use of owned (Box type) heap memory"
-}
-
-#[derive(Copy, Clone)]
-pub struct BoxPointers;
-
-impl BoxPointers {
- fn check_heap_type<'a, 'tcx>(&self, cx: &Context<'a, 'tcx>,
- span: Span, ty: Ty<'tcx>) {
- for leaf_ty in ty.walk() {
- if let ty::TyBox(_) = leaf_ty.sty {
- let m = format!("type uses owned (Box type) pointers: {}", ty);
- cx.span_lint(BOX_POINTERS, span, &m);
- }
- }
- }
-}
-
-impl LintPass for BoxPointers {
- fn get_lints(&self) -> LintArray {
- lint_array!(BOX_POINTERS)
- }
-
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
- match it.node {
- hir::ItemFn(..) |
- hir::ItemTy(..) |
- hir::ItemEnum(..) |
- hir::ItemStruct(..) =>
- self.check_heap_type(cx, it.span,
- cx.tcx.node_id_to_type(it.id)),
- _ => ()
- }
-
- // If it's a struct, we also have to check the fields' types
- match it.node {
- hir::ItemStruct(ref struct_def, _) => {
- for struct_field in &struct_def.fields {
- self.check_heap_type(cx, struct_field.span,
- cx.tcx.node_id_to_type(struct_field.node.id));
- }
- }
- _ => ()
- }
- }
-
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
- let ty = cx.tcx.node_id_to_type(e.id);
- self.check_heap_type(cx, e.span, ty);
- }
-}
-
-declare_lint! {
- RAW_POINTER_DERIVE,
- Warn,
- "uses of #[derive] with raw pointers are rarely correct"
-}
-
-struct RawPtrDeriveVisitor<'a, 'tcx: 'a> {
- cx: &'a Context<'a, 'tcx>
-}
-
-impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> {
- fn visit_ty(&mut self, ty: &hir::Ty) {
- const MSG: &'static str = "use of `#[derive]` with a raw pointer";
- if let hir::TyPtr(..) = ty.node {
- self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG);
- }
- visit::walk_ty(self, ty);
- }
- // explicit override to a no-op to reduce code bloat
- fn visit_expr(&mut self, _: &hir::Expr) {}
- fn visit_block(&mut self, _: &hir::Block) {}
-}
-
-pub struct RawPointerDerive {
- checked_raw_pointers: NodeSet,
-}
-
-impl RawPointerDerive {
- pub fn new() -> RawPointerDerive {
- RawPointerDerive {
- checked_raw_pointers: NodeSet(),
- }
- }
-}
-
-impl LintPass for RawPointerDerive {
- fn get_lints(&self) -> LintArray {
- lint_array!(RAW_POINTER_DERIVE)
- }
-
- fn check_item(&mut self, cx: &Context, item: &hir::Item) {
- if !attr::contains_name(&item.attrs, "automatically_derived") {
- return;
- }
- let did = match item.node {
- hir::ItemImpl(_, _, _, ref t_ref_opt, _, _) => {
- // Deriving the Copy trait does not cause a warning
- if let &Some(ref trait_ref) = t_ref_opt {
- let def_id = cx.tcx.trait_ref_to_def_id(trait_ref);
- if Some(def_id) == cx.tcx.lang_items.copy_trait() {
- return;
- }
- }
-
- match cx.tcx.node_id_to_type(item.id).sty {
- ty::TyEnum(def, _) => def.did,
- ty::TyStruct(def, _) => def.did,
- _ => return,
- }
- }
- _ => return,
- };
- if !did.is_local() {
- return;
- }
- let item = match cx.tcx.map.find(did.node) {
- Some(hir_map::NodeItem(item)) => item,
- _ => return,
- };
- if !self.checked_raw_pointers.insert(item.id) {
- return;
- }
- match item.node {
- hir::ItemStruct(..) | hir::ItemEnum(..) => {
- let mut visitor = RawPtrDeriveVisitor { cx: cx };
- visit::walk_item(&mut visitor, &item);
- }
- _ => {}
- }
- }
-}
-
-declare_lint! {
- UNUSED_ATTRIBUTES,
- Warn,
- "detects attributes that were not used by the compiler"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnusedAttributes;
-
-impl LintPass for UnusedAttributes {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_ATTRIBUTES)
- }
-
- fn check_attribute(&mut self, cx: &Context, attr: &hir::Attribute) {
- // Note that check_name() marks the attribute as used if it matches.
- for &(ref name, ty, _) in KNOWN_ATTRIBUTES {
- match ty {
- AttributeType::Whitelisted if attr.check_name(name) => {
- break;
- },
- _ => ()
- }
- }
-
- let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
- for &(ref name, ty) in plugin_attributes.iter() {
- if ty == AttributeType::Whitelisted && attr.check_name(&*name) {
- break;
- }
- }
-
- if !syntax_attr::is_used(&unlower_attribute(attr)) {
- cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
- // Is it a builtin attribute that must be used at the crate level?
- let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
- attr.name() == name &&
- ty == AttributeType::CrateLevel
- }).is_some();
-
- // Has a plugin registered this attribute as one which must be used at
- // the crate level?
- let plugin_crate = plugin_attributes.iter()
- .find(|&&(ref x, t)| {
- &*attr.name() == &*x &&
- AttributeType::CrateLevel == t
- }).is_some();
- if known_crate || plugin_crate {
- let msg = match attr.node.style {
- hir::AttrOuter => "crate-level attribute should be an inner \
- attribute: add an exclamation mark: #![foo]",
- hir::AttrInner => "crate-level attribute should be in the \
- root module",
- };
- cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
- }
- }
- }
-}
-
-declare_lint! {
- pub PATH_STATEMENTS,
- Warn,
- "path statements with no effect"
-}
-
-#[derive(Copy, Clone)]
-pub struct PathStatements;
-
-impl LintPass for PathStatements {
- fn get_lints(&self) -> LintArray {
- lint_array!(PATH_STATEMENTS)
- }
-
- fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) {
- match s.node {
- hir::StmtSemi(ref expr, _) => {
- match expr.node {
- hir::ExprPath(..) => cx.span_lint(PATH_STATEMENTS, s.span,
- "path statement with no effect"),
- _ => ()
- }
- }
- _ => ()
- }
- }
-}
-
-declare_lint! {
- pub UNUSED_MUST_USE,
- Warn,
- "unused result of a type flagged as #[must_use]"
-}
-
-declare_lint! {
- pub UNUSED_RESULTS,
- Allow,
- "unused result of an expression in a statement"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnusedResults;
-
-impl LintPass for UnusedResults {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS)
- }
-
- fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) {
- let expr = match s.node {
- hir::StmtSemi(ref expr, _) => &**expr,
- _ => return
- };
-
- if let hir::ExprRet(..) = expr.node {
- return;
- }
-
- let t = cx.tcx.expr_ty(&expr);
- let warned = match t.sty {
- ty::TyTuple(ref tys) if tys.is_empty() => return,
- ty::TyBool => return,
- ty::TyStruct(def, _) |
- ty::TyEnum(def, _) => {
- if def.did.is_local() {
- if let hir_map::NodeItem(it) = cx.tcx.map.get(def.did.node) {
- check_must_use(cx, &it.attrs, s.span)
- } else {
- false
- }
- } else {
- let attrs = csearch::get_item_attrs(&cx.sess().cstore, def.did);
- check_must_use(cx, &attrs[..], s.span)
- }
- }
- _ => false,
- };
- if !warned {
- cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
- }
-
- fn check_must_use(cx: &Context, attrs: &[hir::Attribute], sp: Span) -> bool {
- for attr in attrs {
- if attr.check_name("must_use") {
- let mut msg = "unused result which must be used".to_string();
- // check for #[must_use="..."]
- match attr.value_str() {
- None => {}
- Some(s) => {
- msg.push_str(": ");
- msg.push_str(&s);
- }
- }
- cx.span_lint(UNUSED_MUST_USE, sp, &msg);
- return true;
- }
- }
- false
- }
- }
-}
-
-declare_lint! {
- pub NON_CAMEL_CASE_TYPES,
- Warn,
- "types, variants, traits and type parameters should have camel case names"
-}
-
-#[derive(Copy, Clone)]
-pub struct NonCamelCaseTypes;
-
-impl NonCamelCaseTypes {
- fn check_case(&self, cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
- fn is_camel_case(ident: ast::Ident) -> bool {
- let ident = ident.name.as_str();
- if ident.is_empty() {
- return true;
- }
- let ident = ident.trim_matches('_');
-
- // start with a non-lowercase letter rather than non-uppercase
- // ones (some scripts don't have a concept of upper/lowercase)
- !ident.is_empty() && !ident.char_at(0).is_lowercase() && !ident.contains('_')
- }
-
- fn to_camel_case(s: &str) -> String {
- s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)|
- if i == 0 {
- c.to_uppercase().collect::<String>()
- } else {
- c.to_lowercase().collect()
- }
- )).collect::<Vec<_>>().concat()
- }
-
- let s = ident.name.as_str();
-
- if !is_camel_case(ident) {
- let c = to_camel_case(&s);
- let m = if c.is_empty() {
- format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s)
- } else {
- format!("{} `{}` should have a camel case name such as `{}`", sort, s, c)
- };
- cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]);
- }
- }
-}
-
-impl LintPass for NonCamelCaseTypes {
- fn get_lints(&self) -> LintArray {
- lint_array!(NON_CAMEL_CASE_TYPES)
- }
-
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
- let extern_repr_count = it.attrs.iter().filter(|attr| {
- attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
- .any(|r| r == &attr::ReprExtern)
- }).count();
- let has_extern_repr = extern_repr_count > 0;
-
- if has_extern_repr {
- return;
- }
-
- match it.node {
- hir::ItemTy(..) | hir::ItemStruct(..) => {
- self.check_case(cx, "type", it.ident, it.span)
- }
- hir::ItemTrait(..) => {
- self.check_case(cx, "trait", it.ident, it.span)
- }
- hir::ItemEnum(ref enum_definition, _) => {
- if has_extern_repr {
- return;
- }
- self.check_case(cx, "type", it.ident, it.span);
- for variant in &enum_definition.variants {
- self.check_case(cx, "variant", variant.node.name, variant.span);
- }
- }
- _ => ()
- }
- }
-
- fn check_generics(&mut self, cx: &Context, it: &hir::Generics) {
- for gen in it.ty_params.iter() {
- self.check_case(cx, "type parameter", gen.ident, gen.span);
- }
- }
-}
-
-#[derive(PartialEq)]
-enum MethodContext {
- TraitDefaultImpl,
- TraitImpl,
- PlainImpl
-}
-
-fn method_context(cx: &Context, id: ast::NodeId, span: Span) -> MethodContext {
- match cx.tcx.impl_or_trait_items.borrow().get(&DefId::local(id)) {
- None => cx.sess().span_bug(span, "missing method descriptor?!"),
- Some(item) => match item.container() {
- ty::TraitContainer(..) => MethodContext::TraitDefaultImpl,
- ty::ImplContainer(cid) => {
- match cx.tcx.impl_trait_ref(cid) {
- Some(_) => MethodContext::TraitImpl,
- None => MethodContext::PlainImpl
- }
- }
- }
- }
-}
-
-declare_lint! {
- pub NON_SNAKE_CASE,
- Warn,
- "methods, functions, lifetime parameters and modules should have snake case names"
-}
-
-#[derive(Copy, Clone)]
-pub struct NonSnakeCase;
-
-impl NonSnakeCase {
- fn to_snake_case(mut str: &str) -> String {
- let mut words = vec![];
- // Preserve leading underscores
- str = str.trim_left_matches(|c: char| {
- if c == '_' {
- words.push(String::new());
- true
- } else {
- false
- }
- });
- for s in str.split('_') {
- let mut last_upper = false;
- let mut buf = String::new();
- if s.is_empty() {
- continue;
- }
- for ch in s.chars() {
- if !buf.is_empty() && buf != "'"
- && ch.is_uppercase()
- && !last_upper {
- words.push(buf);
- buf = String::new();
- }
- last_upper = ch.is_uppercase();
- buf.extend(ch.to_lowercase());
- }
- words.push(buf);
- }
- words.join("_")
- }
-
- fn check_snake_case(&self, cx: &Context, sort: &str, name: &str, span: Option<Span>) {
- fn is_snake_case(ident: &str) -> bool {
- if ident.is_empty() {
- return true;
- }
- let ident = ident.trim_left_matches('\'');
- let ident = ident.trim_matches('_');
-
- let mut allow_underscore = true;
- ident.chars().all(|c| {
- allow_underscore = match c {
- '_' if !allow_underscore => return false,
- '_' => false,
- // It would be more obvious to use `c.is_lowercase()`,
- // but some characters do not have a lowercase form
- c if !c.is_uppercase() => true,
- _ => return false,
- };
- true
- })
- }
-
- if !is_snake_case(name) {
- let sc = NonSnakeCase::to_snake_case(name);
- let msg = if sc != name {
- format!("{} `{}` should have a snake case name such as `{}`",
- sort, name, sc)
- } else {
- format!("{} `{}` should have a snake case name",
- sort, name)
- };
- match span {
- Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
- None => cx.lint(NON_SNAKE_CASE, &msg),
- }
- }
- }
-}
-
-impl LintPass for NonSnakeCase {
- fn get_lints(&self) -> LintArray {
- lint_array!(NON_SNAKE_CASE)
- }
-
- fn check_crate(&mut self, cx: &Context, cr: &hir::Crate) {
- let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name"))
- .and_then(|at| at.value_str().map(|s| (at, s)));
- if let Some(ref name) = cx.tcx.sess.opts.crate_name {
- self.check_snake_case(cx, "crate", name, None);
- } else if let Some((attr, ref name)) = attr_crate_name {
- self.check_snake_case(cx, "crate", name, Some(attr.span));
- }
- }
-
- fn check_fn(&mut self, cx: &Context,
- fk: FnKind, _: &hir::FnDecl,
- _: &hir::Block, span: Span, id: ast::NodeId) {
- match fk {
- FnKind::Method(ident, _, _) => match method_context(cx, id, span) {
- MethodContext::PlainImpl => {
- self.check_snake_case(cx, "method", &ident.name.as_str(), Some(span))
- },
- MethodContext::TraitDefaultImpl => {
- self.check_snake_case(cx, "trait method", &ident.name.as_str(), Some(span))
- },
- _ => (),
- },
- FnKind::ItemFn(ident, _, _, _, _, _) => {
- self.check_snake_case(cx, "function", &ident.name.as_str(), Some(span))
- },
- _ => (),
- }
- }
-
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
- if let hir::ItemMod(_) = it.node {
- self.check_snake_case(cx, "module", &it.ident.name.as_str(), Some(it.span));
- }
- }
+use bad_style::{MethodLateContext, method_context};
- fn check_trait_item(&mut self, cx: &Context, trait_item: &hir::TraitItem) {
- if let hir::MethodTraitItem(_, None) = trait_item.node {
- self.check_snake_case(cx, "trait method", &trait_item.ident.name.as_str(),
- Some(trait_item.span));
- }
- }
+// hardwired lints from librustc
+pub use lint::builtin::*;
- fn check_lifetime_def(&mut self, cx: &Context, t: &hir::LifetimeDef) {
- self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(),
- Some(t.lifetime.span));
- }
+declare_lint! {
+ WHILE_TRUE,
+ Warn,
+ "suggest using `loop { }` instead of `while true { }`"
+}
- fn check_pat(&mut self, cx: &Context, p: &hir::Pat) {
- if let &hir::PatIdent(_, ref path1, _) = &p.node {
- let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
- if let Some(def::DefLocal(_)) = def {
- self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span));
- }
- }
+#[derive(Copy, Clone)]
+pub struct WhileTrue;
+
+impl LintPass for WhileTrue {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(WHILE_TRUE)
}
+}
- fn check_struct_def(&mut self, cx: &Context, s: &hir::StructDef,
- _: ast::Ident, _: &hir::Generics, _: ast::NodeId) {
- for sf in &s.fields {
- if let hir::StructField_ { kind: hir::NamedField(ident, _), .. } = sf.node {
- self.check_snake_case(cx, "structure field", &ident.name.as_str(),
- Some(sf.span));
+impl LateLintPass for WhileTrue {
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+ if let hir::ExprWhile(ref cond, _, _) = e.node {
+ if let hir::ExprLit(ref lit) = cond.node {
+ if let ast::LitBool(true) = lit.node {
+ cx.span_lint(WHILE_TRUE, e.span,
+ "denote infinite loops with loop { ... }");
+ }
}
}
}
}
declare_lint! {
- pub NON_UPPER_CASE_GLOBALS,
- Warn,
- "static constants should have uppercase identifiers"
+ BOX_POINTERS,
+ Allow,
+ "use of owned (Box type) heap memory"
}
#[derive(Copy, Clone)]
-pub struct NonUpperCaseGlobals;
-
-impl NonUpperCaseGlobals {
- fn check_upper_case(cx: &Context, sort: &str, ident: ast::Ident, span: Span) {
- let s = ident.name.as_str();
-
- if s.chars().any(|c| c.is_lowercase()) {
- let uc = NonSnakeCase::to_snake_case(&s).to_uppercase();
- if uc != &s[..] {
- cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
- &format!("{} `{}` should have an upper case name such as `{}`",
- sort, s, uc));
- } else {
- cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
- &format!("{} `{}` should have an upper case name",
- sort, s));
+pub struct BoxPointers;
+
+impl BoxPointers {
+ fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>,
+ span: Span, ty: Ty<'tcx>) {
+ for leaf_ty in ty.walk() {
+ if let ty::TyBox(_) = leaf_ty.sty {
+ let m = format!("type uses owned (Box type) pointers: {}", ty);
+ cx.span_lint(BOX_POINTERS, span, &m);
}
}
}
}
-impl LintPass for NonUpperCaseGlobals {
+impl LintPass for BoxPointers {
fn get_lints(&self) -> LintArray {
- lint_array!(NON_UPPER_CASE_GLOBALS)
+ lint_array!(BOX_POINTERS)
}
+}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
+impl LateLintPass for BoxPointers {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
- // only check static constants
- hir::ItemStatic(_, hir::MutImmutable, _) => {
- NonUpperCaseGlobals::check_upper_case(cx, "static constant", it.ident, it.span);
- }
- hir::ItemConst(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "constant", it.ident, it.span);
- }
- _ => {}
- }
- }
-
- fn check_trait_item(&mut self, cx: &Context, ti: &hir::TraitItem) {
- match ti.node {
- hir::ConstTraitItem(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
- ti.ident, ti.span);
- }
- _ => {}
+ hir::ItemFn(..) |
+ hir::ItemTy(..) |
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) =>
+ self.check_heap_type(cx, it.span,
+ cx.tcx.node_id_to_type(it.id)),
+ _ => ()
}
- }
- fn check_impl_item(&mut self, cx: &Context, ii: &hir::ImplItem) {
- match ii.node {
- hir::ConstImplItem(..) => {
- NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
- ii.ident, ii.span);
+ // If it's a struct, we also have to check the fields' types
+ match it.node {
+ hir::ItemStruct(ref struct_def, _) => {
+ for struct_field in struct_def.fields() {
+ self.check_heap_type(cx, struct_field.span,
+ cx.tcx.node_id_to_type(struct_field.node.id));
+ }
}
- _ => {}
+ _ => ()
}
}
- fn check_pat(&mut self, cx: &Context, p: &hir::Pat) {
- // Lint for constants that look like binding identifiers (#7526)
- match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
- (&hir::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
- NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
- path1.node, p.span);
- }
- _ => {}
- }
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+ let ty = cx.tcx.node_id_to_type(e.id);
+ self.check_heap_type(cx, e.span, ty);
}
}
declare_lint! {
- UNUSED_PARENS,
+ RAW_POINTER_DERIVE,
Warn,
- "`if`, `match`, `while` and `return` do not need parentheses"
+ "uses of #[derive] with raw pointers are rarely correct"
}
-#[derive(Copy, Clone)]
-pub struct UnusedParens;
-
-impl UnusedParens {
- fn check_unused_parens_core(&self, cx: &Context, value: &hir::Expr, msg: &str,
- struct_lit_needs_parens: bool) {
- if let hir::ExprParen(ref inner) = value.node {
- let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&**inner);
- if !necessary {
- cx.span_lint(UNUSED_PARENS, value.span,
- &format!("unnecessary parentheses around {}", msg))
- }
- }
-
- /// Expressions that syntactically contain an "exterior" struct
- /// literal i.e. not surrounded by any parens or other
- /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
- /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
- /// y: 1 }) == foo` does not.
- fn contains_exterior_struct_lit(value: &hir::Expr) -> bool {
- match value.node {
- hir::ExprStruct(..) => true,
-
- hir::ExprAssign(ref lhs, ref rhs) |
- hir::ExprAssignOp(_, ref lhs, ref rhs) |
- hir::ExprBinary(_, ref lhs, ref rhs) => {
- // X { y: 1 } + X { y: 2 }
- contains_exterior_struct_lit(&**lhs) ||
- contains_exterior_struct_lit(&**rhs)
- }
- hir::ExprUnary(_, ref x) |
- hir::ExprCast(ref x, _) |
- hir::ExprField(ref x, _) |
- hir::ExprTupField(ref x, _) |
- hir::ExprIndex(ref x, _) => {
- // &X { y: 1 }, X { y: 1 }.y
- contains_exterior_struct_lit(&**x)
- }
-
- hir::ExprMethodCall(_, _, ref exprs) => {
- // X { y: 1 }.bar(...)
- contains_exterior_struct_lit(&*exprs[0])
- }
+struct RawPtrDeriveVisitor<'a, 'tcx: 'a> {
+ cx: &'a LateContext<'a, 'tcx>
+}
- _ => false
- }
+impl<'a, 'tcx, 'v> Visitor<'v> for RawPtrDeriveVisitor<'a, 'tcx> {
+ fn visit_ty(&mut self, ty: &hir::Ty) {
+ const MSG: &'static str = "use of `#[derive]` with a raw pointer";
+ if let hir::TyPtr(..) = ty.node {
+ self.cx.span_lint(RAW_POINTER_DERIVE, ty.span, MSG);
}
+ visit::walk_ty(self, ty);
}
+ // explicit override to a no-op to reduce code bloat
+ fn visit_expr(&mut self, _: &hir::Expr) {}
+ fn visit_block(&mut self, _: &hir::Block) {}
}
-impl LintPass for UnusedParens {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_PARENS)
- }
-
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
- let (value, msg, struct_lit_needs_parens) = match e.node {
- hir::ExprIf(ref cond, _, _) => (cond, "`if` condition", true),
- hir::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true),
- hir::ExprMatch(ref head, _, source) => match source {
- hir::MatchSource::Normal => (head, "`match` head expression", true),
- hir::MatchSource::IfLetDesugar { .. } => (head, "`if let` head expression", true),
- hir::MatchSource::WhileLetDesugar => (head, "`while let` head expression", true),
- hir::MatchSource::ForLoopDesugar => (head, "`for` head expression", true),
- },
- hir::ExprRet(Some(ref value)) => (value, "`return` value", false),
- hir::ExprAssign(_, ref value) => (value, "assigned value", false),
- hir::ExprAssignOp(_, _, ref value) => (value, "assigned value", false),
- _ => return
- };
- self.check_unused_parens_core(cx, &**value, msg, struct_lit_needs_parens);
- }
-
- fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) {
- let (value, msg) = match s.node {
- hir::StmtDecl(ref decl, _) => match decl.node {
- hir::DeclLocal(ref local) => match local.init {
- Some(ref value) => (value, "assigned value"),
- None => return
- },
- _ => return
- },
- _ => return
- };
- self.check_unused_parens_core(cx, &**value, msg, false);
- }
+pub struct RawPointerDerive {
+ checked_raw_pointers: NodeSet,
}
-declare_lint! {
- UNUSED_IMPORT_BRACES,
- Allow,
- "unnecessary braces around an imported item"
+impl RawPointerDerive {
+ pub fn new() -> RawPointerDerive {
+ RawPointerDerive {
+ checked_raw_pointers: NodeSet(),
+ }
+ }
}
-#[derive(Copy, Clone)]
-pub struct UnusedImportBraces;
-
-impl LintPass for UnusedImportBraces {
+impl LintPass for RawPointerDerive {
fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_IMPORT_BRACES)
+ lint_array!(RAW_POINTER_DERIVE)
}
+}
- fn check_item(&mut self, cx: &Context, item: &hir::Item) {
- if let hir::ItemUse(ref view_path) = item.node {
- if let hir::ViewPathList(_, ref items) = view_path.node {
- if items.len() == 1 {
- if let hir::PathListIdent {ref name, ..} = items[0].node {
- let m = format!("braces around {} is unnecessary",
- name);
- cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
- &m[..]);
+impl LateLintPass for RawPointerDerive {
+ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
+ if !attr::contains_name(&item.attrs, "automatically_derived") {
+ return;
+ }
+ let did = match item.node {
+ hir::ItemImpl(_, _, _, ref t_ref_opt, _, _) => {
+ // Deriving the Copy trait does not cause a warning
+ if let &Some(ref trait_ref) = t_ref_opt {
+ let def_id = cx.tcx.trait_ref_to_def_id(trait_ref);
+ if Some(def_id) == cx.tcx.lang_items.copy_trait() {
+ return;
}
}
+
+ match cx.tcx.node_id_to_type(item.id).sty {
+ ty::TyEnum(def, _) => def.did,
+ ty::TyStruct(def, _) => def.did,
+ _ => return,
+ }
+ }
+ _ => return,
+ };
+ let node_id = if let Some(node_id) = cx.tcx.map.as_local_node_id(did) {
+ node_id
+ } else {
+ return;
+ };
+ let item = match cx.tcx.map.find(node_id) {
+ Some(hir_map::NodeItem(item)) => item,
+ _ => return,
+ };
+ if !self.checked_raw_pointers.insert(item.id) {
+ return;
+ }
+ match item.node {
+ hir::ItemStruct(..) | hir::ItemEnum(..) => {
+ let mut visitor = RawPtrDeriveVisitor { cx: cx };
+ visit::walk_item(&mut visitor, &item);
}
+ _ => {}
}
}
}
fn get_lints(&self) -> LintArray {
lint_array!(NON_SHORTHAND_FIELD_PATTERNS)
}
+}
- fn check_pat(&mut self, cx: &Context, pat: &hir::Pat) {
+impl LateLintPass for NonShorthandFieldPatterns {
+ fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
let def_map = cx.tcx.def_map.borrow();
if let hir::PatStruct(_, ref v, _) = pat.node {
let field_pats = v.iter().filter(|fieldpat| {
return false;
}
let def = def_map.get(&fieldpat.node.pat.id).map(|d| d.full_def());
- def == Some(def::DefLocal(fieldpat.node.pat.id))
+ if let Some(def_id) = cx.tcx.map.opt_local_def_id(fieldpat.node.pat.id) {
+ def == Some(def::DefLocal(def_id, fieldpat.node.pat.id))
+ } else {
+ false
+ }
});
for fieldpat in field_pats {
if let hir::PatIdent(_, ident, None) = fieldpat.node.pat.node {
- if ident.node.name == fieldpat.node.ident.name {
+ if ident.node.name == fieldpat.node.name {
// FIXME: should this comparison really be done on the name?
// doing it on the ident will fail during compilation of libcore
cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span,
}
}
-declare_lint! {
- pub UNUSED_UNSAFE,
- Warn,
- "unnecessary use of an `unsafe` block"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnusedUnsafe;
-
-impl LintPass for UnusedUnsafe {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_UNSAFE)
- }
-
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
- if let hir::ExprBlock(ref blk) = e.node {
- // Don't warn about generated blocks, that'll just pollute the output.
- if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
- !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
- cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
- }
- }
- }
-}
-
declare_lint! {
UNSAFE_CODE,
Allow,
fn get_lints(&self) -> LintArray {
lint_array!(UNSAFE_CODE)
}
+}
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
+impl LateLintPass for UnsafeCode {
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
if let hir::ExprBlock(ref blk) = e.node {
// Don't warn about generated blocks, that'll just pollute the output.
if blk.rules == hir::UnsafeBlock(hir::UserProvided) {
}
}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemTrait(hir::Unsafety::Unsafe, _, _, _) =>
cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
}
}
- fn check_fn(&mut self, cx: &Context, fk: FnKind, _: &hir::FnDecl,
+ fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
_: &hir::Block, span: Span, _: ast::NodeId) {
match fk {
FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, _, _, _) =>
}
}
- fn check_trait_item(&mut self, cx: &Context, trait_item: &hir::TraitItem) {
+ fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE, trait_item.span,
}
}
-declare_lint! {
- pub UNUSED_MUT,
- Warn,
- "detect mut variables which don't need to be mutable"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnusedMut;
-
-impl UnusedMut {
- fn check_unused_mut_pat(&self, cx: &Context, pats: &[P<hir::Pat>]) {
- // collect all mutable pattern and group their NodeIDs by their Identifier to
- // avoid false warnings in match arms with multiple patterns
-
- let mut mutables = FnvHashMap();
- for p in pats {
- pat_util::pat_bindings(&cx.tcx.def_map, p, |mode, id, _, path1| {
- let ident = path1.node;
- if let hir::BindByValue(hir::MutMutable) = mode {
- if !ident.name.as_str().starts_with("_") {
- match mutables.entry(ident.name.usize()) {
- Vacant(entry) => { entry.insert(vec![id]); },
- Occupied(mut entry) => { entry.get_mut().push(id); },
- }
- }
- }
- });
- }
-
- let used_mutables = cx.tcx.used_mut_nodes.borrow();
- for (_, v) in &mutables {
- if !v.iter().any(|e| used_mutables.contains(e)) {
- cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]),
- "variable does not need to be mutable");
- }
- }
- }
-}
-
-impl LintPass for UnusedMut {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_MUT)
- }
-
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
- if let hir::ExprMatch(_, ref arms, _) = e.node {
- for a in arms {
- self.check_unused_mut_pat(cx, &a.pats)
- }
- }
- }
-
- fn check_stmt(&mut self, cx: &Context, s: &hir::Stmt) {
- if let hir::StmtDecl(ref d, _) = s.node {
- if let hir::DeclLocal(ref l) = d.node {
- self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
- }
- }
- }
-
- fn check_fn(&mut self, cx: &Context,
- _: FnKind, decl: &hir::FnDecl,
- _: &hir::Block, _: Span, _: ast::NodeId) {
- for a in &decl.inputs {
- self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
- }
- }
-}
-
-declare_lint! {
- UNUSED_ALLOCATION,
- Warn,
- "detects unnecessary allocations that can be eliminated"
-}
-
-#[derive(Copy, Clone)]
-pub struct UnusedAllocation;
-
-impl LintPass for UnusedAllocation {
- fn get_lints(&self) -> LintArray {
- lint_array!(UNUSED_ALLOCATION)
- }
-
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
- match e.node {
- hir::ExprUnary(hir::UnUniq, _) => (),
- _ => return
- }
-
- if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
- if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
- ref autoref, ..
- }) = *adjustment {
- match autoref {
- &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
- cx.span_lint(UNUSED_ALLOCATION, e.span,
- "unnecessary allocation, use & instead");
- }
- &Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
- cx.span_lint(UNUSED_ALLOCATION, e.span,
- "unnecessary allocation, use &mut instead");
- }
- _ => ()
- }
- }
- }
- }
-}
-
declare_lint! {
MISSING_DOCS,
Allow,
}
fn check_missing_docs_attrs(&self,
- cx: &Context,
+ cx: &LateContext,
id: Option<ast::NodeId>,
- attrs: &[hir::Attribute],
+ attrs: &[ast::Attribute],
sp: Span,
desc: &'static str) {
// If we're building a test harness, then warning about
let has_doc = attrs.iter().any(|a| {
match a.node.value.node {
- hir::MetaNameValue(ref name, _) if *name == "doc" => true,
+ ast::MetaNameValue(ref name, _) if *name == "doc" => true,
_ => false
}
});
fn get_lints(&self) -> LintArray {
lint_array!(MISSING_DOCS)
}
+}
- fn enter_lint_attrs(&mut self, _: &Context, attrs: &[hir::Attribute]) {
+impl LateLintPass for MissingDoc {
+ fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
attr.check_name("doc") && match attr.meta_item_list() {
None => false,
self.doc_hidden_stack.push(doc_hidden);
}
- fn exit_lint_attrs(&mut self, _: &Context, _: &[hir::Attribute]) {
+ fn exit_lint_attrs(&mut self, _: &LateContext, _: &[ast::Attribute]) {
self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
}
- fn check_struct_def(&mut self, _: &Context, _: &hir::StructDef,
- _: ast::Ident, _: &hir::Generics, id: ast::NodeId) {
- self.struct_def_stack.push(id);
+ fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData,
+ _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
+ self.struct_def_stack.push(item_id);
}
- fn check_struct_def_post(&mut self, _: &Context, _: &hir::StructDef,
- _: ast::Ident, _: &hir::Generics, id: ast::NodeId) {
+ fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData,
+ _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
- assert!(popped == id);
+ assert!(popped == item_id);
}
- fn check_crate(&mut self, cx: &Context, krate: &hir::Crate) {
+ fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) {
self.check_missing_docs_attrs(cx, None, &krate.attrs, krate.span, "crate");
}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
let desc = match it.node {
hir::ItemFn(..) => "a function",
hir::ItemMod(..) => "a module",
// If the trait is private, add the impl items to private_traits so they don't get
// reported for missing docs.
let real_trait = cx.tcx.trait_ref_to_def_id(trait_ref);
- match cx.tcx.map.find(real_trait.node) {
- Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
- for itm in impl_items {
- self.private_traits.insert(itm.id);
- }
- },
- _ => { }
+ if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) {
+ match cx.tcx.map.find(node_id) {
+ Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
+ for itm in impl_items {
+ self.private_traits.insert(itm.id);
+ }
+ },
+ _ => { }
+ }
}
return
},
self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc);
}
- fn check_trait_item(&mut self, cx: &Context, trait_item: &hir::TraitItem) {
+ fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
if self.private_traits.contains(&trait_item.id) { return }
let desc = match trait_item.node {
trait_item.span, desc);
}
- fn check_impl_item(&mut self, cx: &Context, impl_item: &hir::ImplItem) {
+ fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
// If the method is an impl for a trait, don't doc.
- if method_context(cx, impl_item.id, impl_item.span) == MethodContext::TraitImpl {
+ if method_context(cx, impl_item.id, impl_item.span) == MethodLateContext::TraitImpl {
return;
}
impl_item.span, desc);
}
- fn check_struct_field(&mut self, cx: &Context, sf: &hir::StructField) {
+ fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
if let hir::NamedField(_, vis) = sf.node.kind {
if vis == hir::Public || self.in_variant {
let cur_struct_def = *self.struct_def_stack.last()
}
}
- fn check_variant(&mut self, cx: &Context, v: &hir::Variant, _: &hir::Generics) {
- self.check_missing_docs_attrs(cx, Some(v.node.id), &v.node.attrs, v.span, "a variant");
+ fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
+ self.check_missing_docs_attrs(cx, Some(v.node.data.id()),
+ &v.node.attrs, v.span, "a variant");
assert!(!self.in_variant);
self.in_variant = true;
}
- fn check_variant_post(&mut self, _: &Context, _: &hir::Variant, _: &hir::Generics) {
+ fn check_variant_post(&mut self, _: &LateContext, _: &hir::Variant, _: &hir::Generics) {
assert!(self.in_variant);
self.in_variant = false;
}
fn get_lints(&self) -> LintArray {
lint_array!(MISSING_COPY_IMPLEMENTATIONS)
}
+}
- fn check_item(&mut self, cx: &Context, item: &hir::Item) {
+impl LateLintPass for MissingCopyImplementations {
+ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
if !cx.exported_items.contains(&item.id) {
return;
}
if ast_generics.is_parameterized() {
return;
}
- let def = cx.tcx.lookup_adt_def(DefId::local(item.id));
+ let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
(def, cx.tcx.mk_struct(def,
cx.tcx.mk_substs(Substs::empty())))
}
if ast_generics.is_parameterized() {
return;
}
- let def = cx.tcx.lookup_adt_def(DefId::local(item.id));
+ let def = cx.tcx.lookup_adt_def(cx.tcx.map.local_def_id(item.id));
(def, cx.tcx.mk_enum(def,
cx.tcx.mk_substs(Substs::empty())))
}
fn get_lints(&self) -> LintArray {
lint_array!(MISSING_DEBUG_IMPLEMENTATIONS)
}
+}
- fn check_item(&mut self, cx: &Context, item: &hir::Item) {
+impl LateLintPass for MissingDebugImplementations {
+ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
if !cx.exported_items.contains(&item.id) {
return;
}
let debug_def = cx.tcx.lookup_trait_def(debug);
let mut impls = NodeSet();
debug_def.for_each_impl(cx.tcx, |d| {
- if d.is_local() {
- if let Some(ty_def) = cx.tcx.node_id_to_type(d.node).ty_to_def_id() {
- impls.insert(ty_def.node);
+ if let Some(n) = cx.tcx.map.as_local_node_id(d) {
+ if let Some(ty_def) = cx.tcx.node_id_to_type(n).ty_to_def_id() {
+ if let Some(node_id) = cx.tcx.map.as_local_node_id(ty_def) {
+ impls.insert(node_id);
+ }
}
}
});
pub struct Stability;
impl Stability {
- fn lint(&self, cx: &Context, _id: DefId,
+ fn lint(&self, cx: &LateContext, _id: DefId,
span: Span, stability: &Option<&attr::Stability>) {
// Deprecated attributes apply in-crate and cross-crate.
let (lint, label) = match *stability {
- Some(&attr::Stability { deprecated_since: Some(_), .. }) =>
+ Some(&attr::Stability { depr: Some(_), .. }) =>
(DEPRECATED, "deprecated"),
_ => return
};
output(cx, span, stability, lint, label);
- fn output(cx: &Context, span: Span, stability: &Option<&attr::Stability>,
+ fn output(cx: &LateContext, span: Span, stability: &Option<&attr::Stability>,
lint: &'static Lint, label: &'static str) {
let msg = match *stability {
- Some(&attr::Stability { reason: Some(ref s), .. }) => {
- format!("use of {} item: {}", label, *s)
+ Some(&attr::Stability {depr: Some(attr::Deprecation {ref reason, ..}), ..}) => {
+ format!("use of {} item: {}", label, reason)
}
_ => format!("use of {} item", label)
};
}
}
-fn hir_to_ast_stability(stab: &attr::Stability) -> attr::Stability {
- attr::Stability {
- level: match stab.level {
- attr::Unstable => attr::Unstable,
- attr::Stable => attr::Stable,
- },
- feature: stab.feature.clone(),
- since: stab.since.clone(),
- deprecated_since: stab.deprecated_since.clone(),
- reason: stab.reason.clone(),
- issue: stab.issue,
- }
-}
-
impl LintPass for Stability {
fn get_lints(&self) -> LintArray {
lint_array!(DEPRECATED)
}
+}
- fn check_item(&mut self, cx: &Context, item: &hir::Item) {
+impl LateLintPass for Stability {
+ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
stability::check_item(cx.tcx, item, false,
&mut |id, sp, stab|
- self.lint(cx, id, sp,
- &stab.map(|s| hir_to_ast_stability(s)).as_ref()));
+ self.lint(cx, id, sp, &stab));
}
- fn check_expr(&mut self, cx: &Context, e: &hir::Expr) {
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
stability::check_expr(cx.tcx, e,
&mut |id, sp, stab|
- self.lint(cx, id, sp,
- &stab.map(|s| hir_to_ast_stability(s)).as_ref()));
+ self.lint(cx, id, sp, &stab));
}
- fn check_path(&mut self, cx: &Context, path: &hir::Path, id: ast::NodeId) {
+ fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) {
stability::check_path(cx.tcx, path, id,
&mut |id, sp, stab|
- self.lint(cx, id, sp,
- &stab.map(|s| hir_to_ast_stability(s)).as_ref()));
+ self.lint(cx, id, sp, &stab));
+ }
+
+ fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) {
+ stability::check_path_list_item(cx.tcx, item,
+ &mut |id, sp, stab|
+ self.lint(cx, id, sp, &stab));
}
- fn check_pat(&mut self, cx: &Context, pat: &hir::Pat) {
+ fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
stability::check_pat(cx.tcx, pat,
&mut |id, sp, stab|
- self.lint(cx, id, sp,
- &stab.map(|s| hir_to_ast_stability(s)).as_ref()));
+ self.lint(cx, id, sp, &stab));
}
}
fn get_lints(&self) -> LintArray {
lint_array![UNCONDITIONAL_RECURSION]
}
+}
- fn check_fn(&mut self, cx: &Context, fn_kind: FnKind, _: &hir::FnDecl,
+impl LateLintPass for UnconditionalRecursion {
+ fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
blk: &hir::Block, sp: Span, id: ast::NodeId) {
- type F = for<'tcx> fn(&ty::ctxt<'tcx>,
- ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool;
-
let method = match fn_kind {
FnKind::ItemFn(..) => None,
FnKind::Method(..) => {
- cx.tcx.impl_or_trait_item(DefId::local(id)).as_opt_method()
+ cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method()
}
// closures can't recur, so they don't matter.
FnKind::Closure => return
id: ast::NodeId) -> bool {
match tcx.map.get(id) {
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
- tcx.def_map.borrow().get(&callee.id)
- .map_or(false, |def| def.def_id() == DefId::local(fn_id))
+ tcx.def_map
+ .borrow()
+ .get(&callee.id)
+ .map_or(false,
+ |def| def.def_id() == tcx.map.local_def_id(fn_id))
}
_ => false
}
fn expr_refers_to_this_method(tcx: &ty::ctxt,
method: &ty::Method,
id: ast::NodeId) -> bool {
- let tables = tcx.tables.borrow();
-
// Check for method calls and overloaded operators.
- if let Some(m) = tables.method_map.get(&ty::MethodCall::expr(id)) {
+ let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
+ if let Some(m) = opt_m {
if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
return true;
}
}
// Check for overloaded autoderef method calls.
- if let Some(&adjustment::AdjustDerefRef(ref adj)) = tables.adjustments.get(&id) {
+ let opt_adj = tcx.tables.borrow().adjustments.get(&id).cloned();
+ if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
for i in 0..adj.autoderefs {
let method_call = ty::MethodCall::autoderef(id, i as u32);
- if let Some(m) = tables.method_map.get(&method_call) {
+ if let Some(m) = tcx.tables.borrow().method_map
+ .get(&method_call)
+ .cloned() {
if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
return true;
}
hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
match tcx.def_map.borrow().get(&callee.id).map(|d| d.full_def()) {
Some(def::DefMethod(def_id)) => {
- let no_substs = &ty::ItemSubsts::empty();
- let ts = tables.item_substs.get(&callee.id).unwrap_or(no_substs);
- method_call_refers_to_method(tcx, method, def_id, &ts.substs, id)
+ let item_substs =
+ tcx.tables.borrow().item_substs
+ .get(&callee.id)
+ .cloned()
+ .unwrap_or_else(|| ty::ItemSubsts::empty());
+ method_call_refers_to_method(
+ tcx, method, def_id, &item_substs.substs, id)
}
_ => false
}
traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
trait_ref.to_poly_trait_predicate());
- let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node);
+ // unwrap() is ok here b/c `method` is the method
+ // defined in this crate whose body we are
+ // checking, so it's always local
+ let node_id = tcx.map.as_local_node_id(method.def_id).unwrap();
+
+ let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env), false);
let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) {
fn get_lints(&self) -> LintArray {
lint_array![PLUGIN_AS_LIBRARY]
}
+}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
+impl LateLintPass for PluginAsLibrary {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
if cx.sess().plugin_registrar_fn.get().is_some() {
// We're compiling a plugin; it's fine to link other plugins.
return;
PRIVATE_NO_MANGLE_STATICS,
NO_MANGLE_CONST_ITEMS)
}
+}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
+impl LateLintPass for InvalidNoMangleItems {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemFn(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.exported_items.contains(&it.id) {
let msg = format!("function {} is marked #[no_mangle], but not exported",
- it.ident);
+ it.name);
cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
}
},
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.exported_items.contains(&it.id) {
let msg = format!("static {} is marked #[no_mangle], but not exported",
- it.ident);
+ it.name);
cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
}
},
fn get_lints(&self) -> LintArray {
lint_array!(MUTABLE_TRANSMUTES)
}
+}
- fn check_expr(&mut self, cx: &Context, expr: &hir::Expr) {
+impl LateLintPass for MutableTransmutes {
+ fn check_expr(&mut self, cx: &LateContext, expr: &hir::Expr) {
use syntax::abi::RustIntrinsic;
let msg = "mutating transmuted &mut T from &T may cause undefined behavior,\
_ => ()
}
- fn get_transmute_from_to<'a, 'tcx>(cx: &Context<'a, 'tcx>, expr: &hir::Expr)
+ fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
-> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
match expr.node {
hir::ExprPath(..) => (),
None
}
- fn def_id_is_transmute(cx: &Context, def_id: DefId) -> bool {
+ fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
match cx.tcx.lookup_item_type(def_id).ty.sty {
ty::TyBareFn(_, ref bfty) if bfty.abi == RustIntrinsic => (),
_ => return false
fn get_lints(&self) -> LintArray {
lint_array!(UNSTABLE_FEATURES)
}
- fn check_attribute(&mut self, ctx: &Context, attr: &hir::Attribute) {
+}
+
+impl LateLintPass for UnstableFeatures {
+ fn check_attribute(&mut self, ctx: &LateContext, attr: &ast::Attribute) {
if attr::contains_name(&[attr.node.value.clone()], "feature") {
if let Some(items) = attr.node.value.meta_item_list() {
for item in items {
fn get_lints(&self) -> LintArray {
lint_array!(DROP_WITH_REPR_EXTERN)
}
+}
- fn check_crate(&mut self, ctx: &Context, _: &hir::Crate) {
+impl LateLintPass for DropWithReprExtern {
+ fn check_crate(&mut self, ctx: &LateContext, _: &hir::Crate) {
let drop_trait = match ctx.tcx.lang_items.drop_trait() {
Some(id) => ctx.tcx.lookup_trait_def(id), None => { return }
};
codemap::DUMMY_SP);
let self_defn_span = ctx.tcx.map.def_id_span(self_type_did,
codemap::DUMMY_SP);
- ctx.span_lint(DROP_WITH_REPR_EXTERN,
- drop_impl_span,
- "implementing Drop adds hidden state to types, \
- possibly conflicting with `#[repr(C)]`");
- // FIXME #19668: could be span_lint_note instead of manual guard.
- if ctx.current_level(DROP_WITH_REPR_EXTERN) != Level::Allow {
- ctx.sess().span_note(self_defn_span,
- "the `#[repr(C)]` attribute is attached here");
- }
+ ctx.span_lint_note(DROP_WITH_REPR_EXTERN,
+ drop_impl_span,
+ "implementing Drop adds hidden state to types, \
+ possibly conflicting with `#[repr(C)]`",
+ self_defn_span,
+ "the `#[repr(C)]` attribute is attached here");
}
}
_ => {}
#![feature(box_syntax)]
#![feature(num_bits_bytes)]
#![feature(quote)]
-#![feature(ref_slice)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#[macro_use]
extern crate log;
extern crate rustc_front;
+extern crate rustc_back;
pub use rustc::lint as lint;
pub use rustc::metadata as metadata;
use session::Session;
use lint::LintId;
+mod bad_style;
mod builtin;
+mod types;
+mod unused;
+
+use bad_style::*;
+use builtin::*;
+use types::*;
+use unused::*;
/// Tell the `LintStore` about all the built-in lints (the ones
/// defined in this crate and the ones defined in
macro_rules! add_builtin {
($sess:ident, $($name:ident),*,) => (
{$(
- store.register_pass($sess, false, box builtin::$name);
+ store.register_late_pass($sess, false, box $name);
+ )*}
+ )
+ }
+
+ macro_rules! add_early_builtin {
+ ($sess:ident, $($name:ident),*,) => (
+ {$(
+ store.register_early_pass($sess, false, box $name);
)*}
)
}
macro_rules! add_builtin_with_new {
($sess:ident, $($name:ident),*,) => (
{$(
- store.register_pass($sess, false, box builtin::$name::new());
+ store.register_late_pass($sess, false, box $name::new());
)*}
)
}
macro_rules! add_lint_group {
($sess:ident, $name:expr, $($lint:ident),*) => (
- store.register_group($sess, false, $name, vec![$(LintId::of(builtin::$lint)),*]);
+ store.register_group($sess, false, $name, vec![$(LintId::of($lint)),*]);
)
}
+ add_early_builtin!(sess,
+ UnusedParens,
+ );
+
add_builtin!(sess,
HardwiredLints,
WhileTrue,
NonCamelCaseTypes,
NonSnakeCase,
NonUpperCaseGlobals,
- UnusedParens,
UnusedImportBraces,
NonShorthandFieldPatterns,
UnusedUnsafe,
add_lint_group!(sess, "unused",
UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
- UNUSED_UNSAFE, PATH_STATEMENTS);
+ UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
// We have one lint pass defined specially
- store.register_pass(sess, false, box lint::GatherNodeLevels);
+ store.register_late_pass(sess, false, box lint::GatherNodeLevels);
// Insert temporary renamings for a one-time deprecation
store.register_renamed("raw_pointer_deriving", "raw_pointer_derive");
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use middle::{infer};
+use middle::def_id::DefId;
+use middle::subst::Substs;
+use middle::ty::{self, Ty};
+use middle::const_eval::{eval_const_expr_partial, ConstVal};
+use middle::const_eval::EvalHint::ExprTypeChecked;
+use util::nodemap::{FnvHashSet};
+use lint::{LateContext, LintContext, LintArray};
+use lint::{LintPass, LateLintPass};
+
+use std::cmp;
+use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64};
+
+use syntax::{abi, ast};
+use syntax::attr::{self, AttrMetaMethods};
+use syntax::codemap::{self, Span};
+use syntax::feature_gate::{emit_feature_err, GateIssue};
+use syntax::ast::{TyIs, TyUs, TyI8, TyU8, TyI16, TyU16, TyI32, TyU32, TyI64, TyU64};
+
+use rustc_front::hir;
+use rustc_front::visit::{self, Visitor};
+use rustc_front::util::is_shift_binop;
+
+declare_lint! {
+ UNUSED_COMPARISONS,
+ Warn,
+ "comparisons made useless by limits of the types involved"
+}
+
+declare_lint! {
+ OVERFLOWING_LITERALS,
+ Warn,
+ "literal out of range for its type"
+}
+
+declare_lint! {
+ EXCEEDING_BITSHIFTS,
+ Deny,
+ "shift exceeds the type's number of bits"
+}
+
+#[derive(Copy, Clone)]
+pub struct TypeLimits {
+ /// Id of the last visited negated expression
+ negated_expr_id: ast::NodeId,
+}
+
+impl TypeLimits {
+ pub fn new() -> TypeLimits {
+ TypeLimits {
+ negated_expr_id: !0,
+ }
+ }
+}
+
+impl LintPass for TypeLimits {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS)
+ }
+}
+
+impl LateLintPass for TypeLimits {
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+ match e.node {
+ hir::ExprUnary(hir::UnNeg, ref expr) => {
+ match expr.node {
+ hir::ExprLit(ref lit) => {
+ match lit.node {
+ ast::LitInt(_, ast::UnsignedIntLit(_)) => {
+ check_unsigned_negation_feature(cx, e.span);
+ },
+ ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
+ if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
+ check_unsigned_negation_feature(cx, e.span);
+ }
+ },
+ _ => ()
+ }
+ },
+ _ => {
+ let t = cx.tcx.node_id_to_type(expr.id);
+ match t.sty {
+ ty::TyUint(_) => {
+ check_unsigned_negation_feature(cx, e.span);
+ },
+ _ => ()
+ }
+ }
+ };
+ // propagate negation, if the negation itself isn't negated
+ if self.negated_expr_id != e.id {
+ self.negated_expr_id = expr.id;
+ }
+ },
+ hir::ExprBinary(binop, ref l, ref r) => {
+ if is_comparison(binop) && !check_limits(cx.tcx, binop, &**l, &**r) {
+ cx.span_lint(UNUSED_COMPARISONS, e.span,
+ "comparison is useless due to type limits");
+ }
+
+ if is_shift_binop(binop.node) {
+ let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
+ ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
+ ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
+ _ => None
+ };
+
+ if let Some(bits) = opt_ty_bits {
+ let exceeding = if let hir::ExprLit(ref lit) = r.node {
+ if let ast::LitInt(shift, _) = lit.node { shift >= bits }
+ else { false }
+ } else {
+ match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
+ Ok(ConstVal::Int(shift)) => { shift as u64 >= bits },
+ Ok(ConstVal::Uint(shift)) => { shift >= bits },
+ _ => { false }
+ }
+ };
+ if exceeding {
+ cx.span_lint(EXCEEDING_BITSHIFTS, e.span,
+ "bitshift exceeds the type's number of bits");
+ }
+ };
+ }
+ },
+ hir::ExprLit(ref lit) => {
+ match cx.tcx.node_id_to_type(e.id).sty {
+ ty::TyInt(t) => {
+ match lit.node {
+ ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) |
+ ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => {
+ let int_type = if let ast::TyIs = t {
+ cx.sess().target.int_type
+ } else {
+ t
+ };
+ let (_, max) = int_ty_range(int_type);
+ let negative = self.negated_expr_id == e.id;
+
+ // Detect literal value out of range [min, max] inclusive
+ // avoiding use of -min to prevent overflow/panic
+ if (negative && v > max as u64 + 1) ||
+ (!negative && v > max as u64) {
+ cx.span_lint(OVERFLOWING_LITERALS, e.span,
+ &*format!("literal out of range for {:?}", t));
+ return;
+ }
+ }
+ _ => panic!()
+ };
+ },
+ ty::TyUint(t) => {
+ let uint_type = if let ast::TyUs = t {
+ cx.sess().target.uint_type
+ } else {
+ t
+ };
+ let (min, max) = uint_ty_range(uint_type);
+ let lit_val: u64 = match lit.node {
+ ast::LitByte(_v) => return, // _v is u8, within range by definition
+ ast::LitInt(v, _) => v,
+ _ => panic!()
+ };
+ if lit_val < min || lit_val > max {
+ cx.span_lint(OVERFLOWING_LITERALS, e.span,
+ &*format!("literal out of range for {:?}", t));
+ }
+ },
+ ty::TyFloat(t) => {
+ let (min, max) = float_ty_range(t);
+ let lit_val: f64 = match lit.node {
+ ast::LitFloat(ref v, _) |
+ ast::LitFloatUnsuffixed(ref v) => {
+ match v.parse() {
+ Ok(f) => f,
+ Err(_) => return
+ }
+ }
+ _ => panic!()
+ };
+ if lit_val < min || lit_val > max {
+ cx.span_lint(OVERFLOWING_LITERALS, e.span,
+ &*format!("literal out of range for {:?}", t));
+ }
+ },
+ _ => ()
+ };
+ },
+ _ => ()
+ };
+
+ fn is_valid<T:cmp::PartialOrd>(binop: hir::BinOp, v: T,
+ min: T, max: T) -> bool {
+ match binop.node {
+ hir::BiLt => v > min && v <= max,
+ hir::BiLe => v >= min && v < max,
+ hir::BiGt => v >= min && v < max,
+ hir::BiGe => v > min && v <= max,
+ hir::BiEq | hir::BiNe => v >= min && v <= max,
+ _ => panic!()
+ }
+ }
+
+ fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
+ codemap::respan(binop.span, match binop.node {
+ hir::BiLt => hir::BiGt,
+ hir::BiLe => hir::BiGe,
+ hir::BiGt => hir::BiLt,
+ hir::BiGe => hir::BiLe,
+ _ => return binop
+ })
+ }
+
+ // for isize & usize, be conservative with the warnings, so that the
+ // warnings are consistent between 32- and 64-bit platforms
+ fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
+ match int_ty {
+ ast::TyIs => (i64::MIN, i64::MAX),
+ ast::TyI8 => (i8::MIN as i64, i8::MAX as i64),
+ ast::TyI16 => (i16::MIN as i64, i16::MAX as i64),
+ ast::TyI32 => (i32::MIN as i64, i32::MAX as i64),
+ ast::TyI64 => (i64::MIN, i64::MAX)
+ }
+ }
+
+ fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
+ match uint_ty {
+ ast::TyUs => (u64::MIN, u64::MAX),
+ ast::TyU8 => (u8::MIN as u64, u8::MAX as u64),
+ ast::TyU16 => (u16::MIN as u64, u16::MAX as u64),
+ ast::TyU32 => (u32::MIN as u64, u32::MAX as u64),
+ ast::TyU64 => (u64::MIN, u64::MAX)
+ }
+ }
+
+ fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
+ match float_ty {
+ ast::TyF32 => (f32::MIN as f64, f32::MAX as f64),
+ ast::TyF64 => (f64::MIN, f64::MAX)
+ }
+ }
+
+ fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 {
+ match int_ty {
+ ast::TyIs => int_ty_bits(target_int_ty, target_int_ty),
+ ast::TyI8 => i8::BITS as u64,
+ ast::TyI16 => i16::BITS as u64,
+ ast::TyI32 => i32::BITS as u64,
+ ast::TyI64 => i64::BITS as u64
+ }
+ }
+
+ fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 {
+ match uint_ty {
+ ast::TyUs => uint_ty_bits(target_uint_ty, target_uint_ty),
+ ast::TyU8 => u8::BITS as u64,
+ ast::TyU16 => u16::BITS as u64,
+ ast::TyU32 => u32::BITS as u64,
+ ast::TyU64 => u64::BITS as u64
+ }
+ }
+
+ fn check_limits(tcx: &ty::ctxt, binop: hir::BinOp,
+ l: &hir::Expr, r: &hir::Expr) -> bool {
+ let (lit, expr, swap) = match (&l.node, &r.node) {
+ (&hir::ExprLit(_), _) => (l, r, true),
+ (_, &hir::ExprLit(_)) => (r, l, false),
+ _ => return true
+ };
+ // Normalize the binop so that the literal is always on the RHS in
+ // the comparison
+ let norm_binop = if swap {
+ rev_binop(binop)
+ } else {
+ binop
+ };
+ match tcx.node_id_to_type(expr.id).sty {
+ ty::TyInt(int_ty) => {
+ let (min, max) = int_ty_range(int_ty);
+ let lit_val: i64 = match lit.node {
+ hir::ExprLit(ref li) => match li.node {
+ ast::LitInt(v, ast::SignedIntLit(_, ast::Plus)) |
+ ast::LitInt(v, ast::UnsuffixedIntLit(ast::Plus)) => v as i64,
+ ast::LitInt(v, ast::SignedIntLit(_, ast::Minus)) |
+ ast::LitInt(v, ast::UnsuffixedIntLit(ast::Minus)) => -(v as i64),
+ _ => return true
+ },
+ _ => panic!()
+ };
+ is_valid(norm_binop, lit_val, min, max)
+ }
+ ty::TyUint(uint_ty) => {
+ let (min, max): (u64, u64) = uint_ty_range(uint_ty);
+ let lit_val: u64 = match lit.node {
+ hir::ExprLit(ref li) => match li.node {
+ ast::LitInt(v, _) => v,
+ _ => return true
+ },
+ _ => panic!()
+ };
+ is_valid(norm_binop, lit_val, min, max)
+ }
+ _ => true
+ }
+ }
+
+ fn is_comparison(binop: hir::BinOp) -> bool {
+ match binop.node {
+ hir::BiEq | hir::BiLt | hir::BiLe |
+ hir::BiNe | hir::BiGe | hir::BiGt => true,
+ _ => false
+ }
+ }
+
+ fn check_unsigned_negation_feature(cx: &LateContext, span: Span) {
+ if !cx.sess().features.borrow().negate_unsigned {
+ emit_feature_err(
+ &cx.sess().parse_sess.span_diagnostic,
+ "negate_unsigned",
+ span,
+ GateIssue::Language,
+ "unary negation of unsigned integers may be removed in the future");
+ }
+ }
+ }
+}
+
+declare_lint! {
+ IMPROPER_CTYPES,
+ Warn,
+ "proper use of libc types in foreign modules"
+}
+
+struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
+ cx: &'a LateContext<'a, 'tcx>
+}
+
+enum FfiResult {
+ FfiSafe,
+ FfiUnsafe(&'static str),
+ FfiBadStruct(DefId, &'static str),
+ FfiBadEnum(DefId, &'static str)
+}
+
+/// Check if this enum can be safely exported based on the
+/// "nullable pointer optimization". Currently restricted
+/// to function pointers and references, but could be
+/// expanded to cover NonZero raw pointers and newtypes.
+/// FIXME: This duplicates code in trans.
+fn is_repr_nullable_ptr<'tcx>(tcx: &ty::ctxt<'tcx>,
+ def: ty::AdtDef<'tcx>,
+ substs: &Substs<'tcx>)
+ -> bool {
+ if def.variants.len() == 2 {
+ let data_idx;
+
+ if def.variants[0].fields.is_empty() {
+ data_idx = 1;
+ } else if def.variants[1].fields.is_empty() {
+ data_idx = 0;
+ } else {
+ return false;
+ }
+
+ if def.variants[data_idx].fields.len() == 1 {
+ match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
+ ty::TyBareFn(None, _) => { return true; }
+ ty::TyRef(..) => { return true; }
+ _ => { }
+ }
+ }
+ }
+ false
+}
+
+fn ast_ty_to_normalized<'tcx>(tcx: &ty::ctxt<'tcx>,
+ id: ast::NodeId)
+ -> Ty<'tcx> {
+ let tty = match tcx.ast_ty_to_ty_cache.borrow().get(&id) {
+ Some(&t) => t,
+ None => panic!("ast_ty_to_ty_cache was incomplete after typeck!")
+ };
+ infer::normalize_associated_type(tcx, &tty)
+}
+
+impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
+ /// Check if the given type is "ffi-safe" (has a stable, well-defined
+ /// representation which can be exported to C code).
+ fn check_type_for_ffi(&self,
+ cache: &mut FnvHashSet<Ty<'tcx>>,
+ ty: Ty<'tcx>)
+ -> FfiResult {
+ use self::FfiResult::*;
+ let cx = &self.cx.tcx;
+
+ // Protect against infinite recursion, for example
+ // `struct S(*mut S);`.
+ // FIXME: A recursion limit is necessary as well, for irregular
+ // recusive types.
+ if !cache.insert(ty) {
+ return FfiSafe;
+ }
+
+ match ty.sty {
+ ty::TyStruct(def, substs) => {
+ if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+ return FfiUnsafe(
+ "found struct without foreign-function-safe \
+ representation annotation in foreign module, \
+ consider adding a #[repr(C)] attribute to \
+ the type");
+ }
+
+ // We can't completely trust repr(C) markings; make sure the
+ // fields are actually safe.
+ if def.struct_variant().fields.is_empty() {
+ return FfiUnsafe(
+ "found zero-size struct in foreign module, consider \
+ adding a member to this struct");
+ }
+
+ for field in &def.struct_variant().fields {
+ let field_ty = infer::normalize_associated_type(cx, &field.ty(cx, substs));
+ let r = self.check_type_for_ffi(cache, field_ty);
+ match r {
+ FfiSafe => {}
+ FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+ FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
+ }
+ }
+ FfiSafe
+ }
+ ty::TyEnum(def, substs) => {
+ if def.variants.is_empty() {
+ // Empty enums are okay... although sort of useless.
+ return FfiSafe
+ }
+
+ // Check for a repr() attribute to specify the size of the
+ // discriminant.
+ let repr_hints = cx.lookup_repr_hints(def.did);
+ match &**repr_hints {
+ [] => {
+ // Special-case types like `Option<extern fn()>`.
+ if !is_repr_nullable_ptr(cx, def, substs) {
+ return FfiUnsafe(
+ "found enum without foreign-function-safe \
+ representation annotation in foreign module, \
+ consider adding a #[repr(...)] attribute to \
+ the type")
+ }
+ }
+ [ref hint] => {
+ if !hint.is_ffi_safe() {
+ // FIXME: This shouldn't be reachable: we should check
+ // this earlier.
+ return FfiUnsafe(
+ "enum has unexpected #[repr(...)] attribute")
+ }
+
+ // Enum with an explicitly sized discriminant; either
+ // a C-style enum or a discriminated union.
+
+ // The layout of enum variants is implicitly repr(C).
+ // FIXME: Is that correct?
+ }
+ _ => {
+ // FIXME: This shouldn't be reachable: we should check
+ // this earlier.
+ return FfiUnsafe(
+ "enum has too many #[repr(...)] attributes");
+ }
+ }
+
+ // Check the contained variants.
+ for variant in &def.variants {
+ for field in &variant.fields {
+ let arg = infer::normalize_associated_type(cx, &field.ty(cx, substs));
+ let r = self.check_type_for_ffi(cache, arg);
+ match r {
+ FfiSafe => {}
+ FfiBadStruct(..) | FfiBadEnum(..) => { return r; }
+ FfiUnsafe(s) => { return FfiBadEnum(def.did, s); }
+ }
+ }
+ }
+ FfiSafe
+ }
+
+ ty::TyChar => {
+ FfiUnsafe("found Rust type `char` in foreign module, while \
+ `u32` or `libc::wchar_t` should be used")
+ }
+
+ // Primitive types with a stable representation.
+ ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
+ ty::TyFloat(..) => FfiSafe,
+
+ ty::TyBox(..) => {
+ FfiUnsafe("found Rust type Box<_> in foreign module, \
+ consider using a raw pointer instead")
+ }
+
+ ty::TySlice(_) => {
+ FfiUnsafe("found Rust slice type in foreign module, \
+ consider using a raw pointer instead")
+ }
+
+ ty::TyTrait(..) => {
+ FfiUnsafe("found Rust trait type in foreign module, \
+ consider using a raw pointer instead")
+ }
+
+ ty::TyStr => {
+ FfiUnsafe("found Rust type `str` in foreign module; \
+ consider using a `*const libc::c_char`")
+ }
+
+ ty::TyTuple(_) => {
+ FfiUnsafe("found Rust tuple type in foreign module; \
+ consider using a struct instead`")
+ }
+
+ ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
+ self.check_type_for_ffi(cache, m.ty)
+ }
+
+ ty::TyArray(ty, _) => {
+ self.check_type_for_ffi(cache, ty)
+ }
+
+ ty::TyBareFn(None, bare_fn) => {
+ match bare_fn.abi {
+ abi::Rust |
+ abi::RustIntrinsic |
+ abi::PlatformIntrinsic |
+ abi::RustCall => {
+ return FfiUnsafe(
+ "found function pointer with Rust calling \
+ convention in foreign module; consider using an \
+ `extern` function pointer")
+ }
+ _ => {}
+ }
+
+ let sig = cx.erase_late_bound_regions(&bare_fn.sig);
+ match sig.output {
+ ty::FnDiverging => {}
+ ty::FnConverging(output) => {
+ if !output.is_nil() {
+ let r = self.check_type_for_ffi(cache, output);
+ match r {
+ FfiSafe => {}
+ _ => { return r; }
+ }
+ }
+ }
+ }
+ for arg in sig.inputs {
+ let r = self.check_type_for_ffi(cache, arg);
+ match r {
+ FfiSafe => {}
+ _ => { return r; }
+ }
+ }
+ FfiSafe
+ }
+
+ ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
+ ty::TyClosure(..) | ty::TyProjection(..) |
+ ty::TyBareFn(Some(_), _) => {
+ panic!("Unexpected type in foreign function")
+ }
+ }
+ }
+
+ fn check_def(&mut self, sp: Span, id: ast::NodeId) {
+ let tty = ast_ty_to_normalized(self.cx.tcx, id);
+
+ match ImproperCTypesVisitor::check_type_for_ffi(self, &mut FnvHashSet(), tty) {
+ FfiResult::FfiSafe => {}
+ FfiResult::FfiUnsafe(s) => {
+ self.cx.span_lint(IMPROPER_CTYPES, sp, s);
+ }
+ FfiResult::FfiBadStruct(_, s) => {
+ // FIXME: This diagnostic is difficult to read, and doesn't
+ // point at the relevant field.
+ self.cx.span_lint(IMPROPER_CTYPES, sp,
+ &format!("found non-foreign-function-safe member in \
+ struct marked #[repr(C)]: {}", s));
+ }
+ FfiResult::FfiBadEnum(_, s) => {
+ // FIXME: This diagnostic is difficult to read, and doesn't
+ // point at the relevant variant.
+ self.cx.span_lint(IMPROPER_CTYPES, sp,
+ &format!("found non-foreign-function-safe member in \
+ enum: {}", s));
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> {
+ fn visit_ty(&mut self, ty: &hir::Ty) {
+ match ty.node {
+ hir::TyPath(..) |
+ hir::TyBareFn(..) => self.check_def(ty.span, ty.id),
+ hir::TyVec(..) => {
+ self.cx.span_lint(IMPROPER_CTYPES, ty.span,
+ "found Rust slice type in foreign module, consider \
+ using a raw pointer instead");
+ }
+ hir::TyFixedLengthVec(ref ty, _) => self.visit_ty(ty),
+ hir::TyTup(..) => {
+ self.cx.span_lint(IMPROPER_CTYPES, ty.span,
+ "found Rust tuple type in foreign module; \
+ consider using a struct instead`")
+ }
+ _ => visit::walk_ty(self, ty)
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub struct ImproperCTypes;
+
+impl LintPass for ImproperCTypes {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(IMPROPER_CTYPES)
+ }
+}
+
+impl LateLintPass for ImproperCTypes {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ fn check_ty(cx: &LateContext, ty: &hir::Ty) {
+ let mut vis = ImproperCTypesVisitor { cx: cx };
+ vis.visit_ty(ty);
+ }
+
+ fn check_foreign_fn(cx: &LateContext, decl: &hir::FnDecl) {
+ for input in &decl.inputs {
+ check_ty(cx, &*input.ty);
+ }
+ if let hir::Return(ref ret_ty) = decl.output {
+ let tty = ast_ty_to_normalized(cx.tcx, ret_ty.id);
+ if !tty.is_nil() {
+ check_ty(cx, &ret_ty);
+ }
+ }
+ }
+
+ match it.node {
+ hir::ItemForeignMod(ref nmod)
+ if nmod.abi != abi::RustIntrinsic &&
+ nmod.abi != abi::PlatformIntrinsic => {
+ for ni in &nmod.items {
+ match ni.node {
+ hir::ForeignItemFn(ref decl, _) => check_foreign_fn(cx, &**decl),
+ hir::ForeignItemStatic(ref t, _) => check_ty(cx, &**t)
+ }
+ }
+ }
+ _ => (),
+ }
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use metadata::csearch;
+use middle::pat_util;
+use middle::ty;
+use middle::ty::adjustment;
+use rustc::front::map as hir_map;
+use util::nodemap::FnvHashMap;
+use lint::{LateContext, EarlyContext, LintContext, LintArray};
+use lint::{LintPass, EarlyLintPass, LateLintPass};
+
+use std::collections::hash_map::Entry::{Occupied, Vacant};
+
+use syntax::ast;
+use syntax::attr::{self, AttrMetaMethods};
+use syntax::codemap::Span;
+use syntax::feature_gate::{KNOWN_ATTRIBUTES, AttributeType};
+use syntax::ptr::P;
+
+use rustc_back::slice;
+use rustc_front::hir;
+use rustc_front::visit::FnKind;
+
+declare_lint! {
+ pub UNUSED_MUT,
+ Warn,
+ "detect mut variables which don't need to be mutable"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedMut;
+
+impl UnusedMut {
+ fn check_unused_mut_pat(&self, cx: &LateContext, pats: &[P<hir::Pat>]) {
+ // collect all mutable pattern and group their NodeIDs by their Identifier to
+ // avoid false warnings in match arms with multiple patterns
+
+ let mut mutables = FnvHashMap();
+ for p in pats {
+ pat_util::pat_bindings(&cx.tcx.def_map, p, |mode, id, _, path1| {
+ let name = path1.node;
+ if let hir::BindByValue(hir::MutMutable) = mode {
+ if !name.as_str().starts_with("_") {
+ match mutables.entry(name.0 as usize) {
+ Vacant(entry) => { entry.insert(vec![id]); },
+ Occupied(mut entry) => { entry.get_mut().push(id); },
+ }
+ }
+ }
+ });
+ }
+
+ let used_mutables = cx.tcx.used_mut_nodes.borrow();
+ for (_, v) in &mutables {
+ if !v.iter().any(|e| used_mutables.contains(e)) {
+ cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]),
+ "variable does not need to be mutable");
+ }
+ }
+ }
+}
+
+impl LintPass for UnusedMut {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_MUT)
+ }
+}
+
+impl LateLintPass for UnusedMut {
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+ if let hir::ExprMatch(_, ref arms, _) = e.node {
+ for a in arms {
+ self.check_unused_mut_pat(cx, &a.pats)
+ }
+ }
+ }
+
+ fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
+ if let hir::StmtDecl(ref d, _) = s.node {
+ if let hir::DeclLocal(ref l) = d.node {
+ self.check_unused_mut_pat(cx, slice::ref_slice(&l.pat));
+ }
+ }
+ }
+
+ fn check_fn(&mut self, cx: &LateContext,
+ _: FnKind, decl: &hir::FnDecl,
+ _: &hir::Block, _: Span, _: ast::NodeId) {
+ for a in &decl.inputs {
+ self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
+ }
+ }
+}
+
+declare_lint! {
+ pub UNUSED_MUST_USE,
+ Warn,
+ "unused result of a type flagged as #[must_use]"
+}
+
+declare_lint! {
+ pub UNUSED_RESULTS,
+ Allow,
+ "unused result of an expression in a statement"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedResults;
+
+impl LintPass for UnusedResults {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_MUST_USE, UNUSED_RESULTS)
+ }
+}
+
+impl LateLintPass for UnusedResults {
+ fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
+ let expr = match s.node {
+ hir::StmtSemi(ref expr, _) => &**expr,
+ _ => return
+ };
+
+ if let hir::ExprRet(..) = expr.node {
+ return;
+ }
+
+ let t = cx.tcx.expr_ty(&expr);
+ let warned = match t.sty {
+ ty::TyTuple(ref tys) if tys.is_empty() => return,
+ ty::TyBool => return,
+ ty::TyStruct(def, _) |
+ ty::TyEnum(def, _) => {
+ if let Some(def_node_id) = cx.tcx.map.as_local_node_id(def.did) {
+ if let hir_map::NodeItem(it) = cx.tcx.map.get(def_node_id) {
+ check_must_use(cx, &it.attrs, s.span)
+ } else {
+ false
+ }
+ } else {
+ let attrs = csearch::get_item_attrs(&cx.sess().cstore, def.did);
+ check_must_use(cx, &attrs[..], s.span)
+ }
+ }
+ _ => false,
+ };
+ if !warned {
+ cx.span_lint(UNUSED_RESULTS, s.span, "unused result");
+ }
+
+ fn check_must_use(cx: &LateContext, attrs: &[ast::Attribute], sp: Span) -> bool {
+ for attr in attrs {
+ if attr.check_name("must_use") {
+ let mut msg = "unused result which must be used".to_string();
+ // check for #[must_use="..."]
+ match attr.value_str() {
+ None => {}
+ Some(s) => {
+ msg.push_str(": ");
+ msg.push_str(&s);
+ }
+ }
+ cx.span_lint(UNUSED_MUST_USE, sp, &msg);
+ return true;
+ }
+ }
+ false
+ }
+ }
+}
+
+declare_lint! {
+ pub UNUSED_UNSAFE,
+ Warn,
+ "unnecessary use of an `unsafe` block"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedUnsafe;
+
+impl LintPass for UnusedUnsafe {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_UNSAFE)
+ }
+}
+
+impl LateLintPass for UnusedUnsafe {
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+ if let hir::ExprBlock(ref blk) = e.node {
+ // Don't warn about generated blocks, that'll just pollute the output.
+ if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
+ !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
+ cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
+ }
+ }
+ }
+}
+
+declare_lint! {
+ pub PATH_STATEMENTS,
+ Warn,
+ "path statements with no effect"
+}
+
+#[derive(Copy, Clone)]
+pub struct PathStatements;
+
+impl LintPass for PathStatements {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(PATH_STATEMENTS)
+ }
+}
+
+impl LateLintPass for PathStatements {
+ fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
+ match s.node {
+ hir::StmtSemi(ref expr, _) => {
+ match expr.node {
+ hir::ExprPath(..) => cx.span_lint(PATH_STATEMENTS, s.span,
+ "path statement with no effect"),
+ _ => ()
+ }
+ }
+ _ => ()
+ }
+ }
+}
+
+declare_lint! {
+ pub UNUSED_ATTRIBUTES,
+ Warn,
+ "detects attributes that were not used by the compiler"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedAttributes;
+
+impl LintPass for UnusedAttributes {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_ATTRIBUTES)
+ }
+}
+
+impl LateLintPass for UnusedAttributes {
+ fn check_attribute(&mut self, cx: &LateContext, attr: &ast::Attribute) {
+ // Note that check_name() marks the attribute as used if it matches.
+ for &(ref name, ty, _) in KNOWN_ATTRIBUTES {
+ match ty {
+ AttributeType::Whitelisted if attr.check_name(name) => {
+ break;
+ },
+ _ => ()
+ }
+ }
+
+ let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
+ for &(ref name, ty) in plugin_attributes.iter() {
+ if ty == AttributeType::Whitelisted && attr.check_name(&*name) {
+ break;
+ }
+ }
+
+ if !attr::is_used(attr) {
+ cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
+ // Is it a builtin attribute that must be used at the crate level?
+ let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
+ attr.name() == name &&
+ ty == AttributeType::CrateLevel
+ }).is_some();
+
+ // Has a plugin registered this attribute as one which must be used at
+ // the crate level?
+ let plugin_crate = plugin_attributes.iter()
+ .find(|&&(ref x, t)| {
+ &*attr.name() == &*x &&
+ AttributeType::CrateLevel == t
+ }).is_some();
+ if known_crate || plugin_crate {
+ let msg = match attr.node.style {
+ ast::AttrStyle::Outer => "crate-level attribute should be an inner \
+ attribute: add an exclamation mark: #![foo]",
+ ast::AttrStyle::Inner => "crate-level attribute should be in the \
+ root module",
+ };
+ cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
+ }
+ }
+ }
+}
+
+declare_lint! {
+ UNUSED_PARENS,
+ Warn,
+ "`if`, `match`, `while` and `return` do not need parentheses"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedParens;
+
+impl UnusedParens {
+ fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str,
+ struct_lit_needs_parens: bool) {
+ if let ast::ExprParen(ref inner) = value.node {
+ let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&**inner);
+ if !necessary {
+ cx.span_lint(UNUSED_PARENS, value.span,
+ &format!("unnecessary parentheses around {}", msg))
+ }
+ }
+
+ /// Expressions that syntactically contain an "exterior" struct
+ /// literal i.e. not surrounded by any parens or other
+ /// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
+ /// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
+ /// y: 1 }) == foo` does not.
+ fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
+ match value.node {
+ ast::ExprStruct(..) => true,
+
+ ast::ExprAssign(ref lhs, ref rhs) |
+ ast::ExprAssignOp(_, ref lhs, ref rhs) |
+ ast::ExprBinary(_, ref lhs, ref rhs) => {
+ // X { y: 1 } + X { y: 2 }
+ contains_exterior_struct_lit(&**lhs) ||
+ contains_exterior_struct_lit(&**rhs)
+ }
+ ast::ExprUnary(_, ref x) |
+ ast::ExprCast(ref x, _) |
+ ast::ExprField(ref x, _) |
+ ast::ExprTupField(ref x, _) |
+ ast::ExprIndex(ref x, _) => {
+ // &X { y: 1 }, X { y: 1 }.y
+ contains_exterior_struct_lit(&**x)
+ }
+
+ ast::ExprMethodCall(_, _, ref exprs) => {
+ // X { y: 1 }.bar(...)
+ contains_exterior_struct_lit(&*exprs[0])
+ }
+
+ _ => false
+ }
+ }
+ }
+}
+
+impl LintPass for UnusedParens {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_PARENS)
+ }
+}
+
+impl EarlyLintPass for UnusedParens {
+ fn check_expr(&mut self, cx: &EarlyContext, e: &ast::Expr) {
+ let (value, msg, struct_lit_needs_parens) = match e.node {
+ ast::ExprIf(ref cond, _, _) => (cond, "`if` condition", true),
+ ast::ExprWhile(ref cond, _, _) => (cond, "`while` condition", true),
+ ast::ExprIfLet(_, ref cond, _, _) => (cond, "`if let` head expression", true),
+ ast::ExprWhileLet(_, ref cond, _, _) => (cond, "`while let` head expression", true),
+ ast::ExprForLoop(_, ref cond, _, _) => (cond, "`for` head expression", true),
+ ast::ExprMatch(ref head, _) => (head, "`match` head expression", true),
+ ast::ExprRet(Some(ref value)) => (value, "`return` value", false),
+ ast::ExprAssign(_, ref value) => (value, "assigned value", false),
+ ast::ExprAssignOp(_, _, ref value) => (value, "assigned value", false),
+ _ => return
+ };
+ self.check_unused_parens_core(cx, &**value, msg, struct_lit_needs_parens);
+ }
+
+ fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
+ let (value, msg) = match s.node {
+ ast::StmtDecl(ref decl, _) => match decl.node {
+ ast::DeclLocal(ref local) => match local.init {
+ Some(ref value) => (value, "assigned value"),
+ None => return
+ },
+ _ => return
+ },
+ _ => return
+ };
+ self.check_unused_parens_core(cx, &**value, msg, false);
+ }
+}
+
+declare_lint! {
+ UNUSED_IMPORT_BRACES,
+ Allow,
+ "unnecessary braces around an imported item"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedImportBraces;
+
+impl LintPass for UnusedImportBraces {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_IMPORT_BRACES)
+ }
+}
+
+impl LateLintPass for UnusedImportBraces {
+ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
+ if let hir::ItemUse(ref view_path) = item.node {
+ if let hir::ViewPathList(_, ref items) = view_path.node {
+ if items.len() == 1 {
+ if let hir::PathListIdent {ref name, ..} = items[0].node {
+ let m = format!("braces around {} is unnecessary",
+ name);
+ cx.span_lint(UNUSED_IMPORT_BRACES, item.span,
+ &m[..]);
+ }
+ }
+ }
+ }
+ }
+}
+
+declare_lint! {
+ UNUSED_ALLOCATION,
+ Warn,
+ "detects unnecessary allocations that can be eliminated"
+}
+
+#[derive(Copy, Clone)]
+pub struct UnusedAllocation;
+
+impl LintPass for UnusedAllocation {
+ fn get_lints(&self) -> LintArray {
+ lint_array!(UNUSED_ALLOCATION)
+ }
+}
+
+impl LateLintPass for UnusedAllocation {
+ fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
+ match e.node {
+ hir::ExprBox(_) => {}
+ _ => return
+ }
+
+ if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
+ if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
+ ref autoref, ..
+ }) = *adjustment {
+ match autoref {
+ &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
+ cx.span_lint(UNUSED_ALLOCATION, e.span,
+ "unnecessary allocation, use & instead");
+ }
+ &Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
+ cx.span_lint(UNUSED_ALLOCATION, e.span,
+ "unnecessary allocation, use &mut instead");
+ }
+ _ => ()
+ }
+ }
+ }
+ }
+}
+
use std::ffi::CString;
use std::cell::RefCell;
-use std::{slice, mem};
+use std::slice;
use libc::{c_uint, c_ushort, uint64_t, c_int, size_t, c_char};
use libc::{c_longlong, c_ulonglong, c_void};
use debuginfo::{DIBuilderRef, DIDescriptor,
size: size_t) {
let slice = slice::from_raw_parts(ptr as *const u8, size as usize);
- let sr: RustStringRepr = mem::transmute(sr);
+ let sr = sr as RustStringRepr;
(*sr).borrow_mut().push_all(slice);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use build::{BlockAnd, Builder};
use hair::*;
use repr::*;
-use build::{BlockAnd, Builder};
+use rustc_front::hir;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
pub fn ast_block(&mut self,
- destination: &Lvalue<H>,
+ destination: &Lvalue<'tcx>,
mut block: BasicBlock,
- ast_block: H::Block)
+ ast_block: &'tcx hir::Block)
-> BlockAnd<()> {
let this = self;
let Block { extent, span: _, stmts, expr } = this.hir.mirror(ast_block);
//! Routines for manipulating the control-flow graph.
use build::CFG;
-use hair::*;
use repr::*;
+use syntax::codemap::Span;
-impl<H:Hair> CFG<H> {
- pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<H> {
+impl<'tcx> CFG<'tcx> {
+ pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
&self.basic_blocks[blk.index()]
}
- pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<H> {
+ pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
&mut self.basic_blocks[blk.index()]
}
pub fn end_point(&self, block: BasicBlock) -> ExecutionPoint {
ExecutionPoint {
block: block,
- statement: self.block_data(block).statements.len() as u32
+ statement: self.block_data(block).statements.len() as u32,
}
}
BasicBlock::new(node_index)
}
- pub fn push(&mut self, block: BasicBlock, statement: Statement<H>) {
+ pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
debug!("push({:?}, {:?})", block, statement);
self.block_data_mut(block).statements.push(statement);
}
pub fn push_assign_constant(&mut self,
block: BasicBlock,
- span: H::Span,
- temp: &Lvalue<H>,
- constant: Constant<H>) {
+ span: Span,
+ temp: &Lvalue<'tcx>,
+ constant: Constant<'tcx>) {
self.push_assign(block, span, temp, Rvalue::Use(Operand::Constant(constant)));
}
- pub fn push_drop(&mut self, block: BasicBlock, span: H::Span,
- kind: DropKind, lvalue: &Lvalue<H>) {
+ pub fn push_drop(&mut self, block: BasicBlock, span: Span,
+ kind: DropKind, lvalue: &Lvalue<'tcx>) {
self.push(block, Statement {
span: span,
kind: StatementKind::Drop(kind, lvalue.clone())
pub fn push_assign(&mut self,
block: BasicBlock,
- span: H::Span,
- lvalue: &Lvalue<H>,
- rvalue: Rvalue<H>) {
+ span: Span,
+ lvalue: &Lvalue<'tcx>,
+ rvalue: Rvalue<'tcx>) {
self.push(block, Statement {
span: span,
kind: StatementKind::Assign(lvalue.clone(), rvalue)
pub fn terminate(&mut self,
block: BasicBlock,
- terminator: Terminator<H>) {
+ terminator: Terminator<'tcx>) {
// Check whether this block has already been terminated. For
// this, we rely on the fact that the initial state is to have
// a Diverge terminator and an empty list of targets (which
//! See docs in build/expr/mod.rs
-use rustc_data_structures::fnv::FnvHashMap;
-
-use build::{Builder};
+use build::Builder;
use hair::*;
use repr::*;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Compile `expr`, yielding a compile-time constant. Assumes that
/// `expr` is a valid compile-time constant!
- pub fn as_constant<M>(&mut self, expr: M) -> Constant<H>
- where M: Mirror<H, Output=Expr<H>>
+ pub fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
+ where M: Mirror<'tcx, Output=Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_constant(expr)
}
- fn expr_as_constant(&mut self, expr: Expr<H>) -> Constant<H> {
+ fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
let this = self;
- let Expr { ty: _, temp_lifetime: _, span, kind } = expr;
- let kind = match kind {
- ExprKind::Scope { extent: _, value } => {
- return this.as_constant(value);
- }
- ExprKind::Paren { arg } => {
- return this.as_constant(arg);
- }
- ExprKind::Literal { literal } => {
- ConstantKind::Literal(literal)
- }
- ExprKind::Vec { fields } => {
- let fields = this.as_constants(fields);
- ConstantKind::Aggregate(AggregateKind::Vec, fields)
- }
- ExprKind::Tuple { fields } => {
- let fields = this.as_constants(fields);
- ConstantKind::Aggregate(AggregateKind::Tuple, fields)
- }
- ExprKind::Adt { adt_def, variant_index, substs, fields, base: None } => {
- let field_names = this.hir.fields(adt_def, variant_index);
- let fields = this.named_field_constants(field_names, fields);
- ConstantKind::Aggregate(AggregateKind::Adt(adt_def, variant_index, substs), fields)
- }
- ExprKind::Repeat { value, count } => {
- let value = Box::new(this.as_constant(value));
- let count = Box::new(this.as_constant(count));
- ConstantKind::Repeat(value, count)
- }
- ExprKind::Binary { op, lhs, rhs } => {
- let lhs = Box::new(this.as_constant(lhs));
- let rhs = Box::new(this.as_constant(rhs));
- ConstantKind::BinaryOp(op, lhs, rhs)
- }
- ExprKind::Unary { op, arg } => {
- let arg = Box::new(this.as_constant(arg));
- ConstantKind::UnaryOp(op, arg)
- }
- ExprKind::Field { lhs, name } => {
- let lhs = this.as_constant(lhs);
- ConstantKind::Projection(
- Box::new(ConstantProjection {
- base: lhs,
- elem: ProjectionElem::Field(name),
- }))
- }
- ExprKind::Deref { arg } => {
- let arg = this.as_constant(arg);
- ConstantKind::Projection(
- Box::new(ConstantProjection {
- base: arg,
- elem: ProjectionElem::Deref,
- }))
- }
- ExprKind::Call { fun, args } => {
- let fun = this.as_constant(fun);
- let args = this.as_constants(args);
- ConstantKind::Call(Box::new(fun), args)
- }
- _ => {
+ let Expr { ty, temp_lifetime: _, span, kind } = expr;
+ match kind {
+ ExprKind::Scope { extent: _, value } =>
+ this.as_constant(value),
+ ExprKind::Literal { literal } =>
+ Constant { span: span, ty: ty, literal: literal },
+ _ =>
this.hir.span_bug(
span,
- &format!("expression is not a valid constant {:?}", kind));
- }
- };
- Constant { span: span, kind: kind }
- }
-
- fn as_constants(&mut self,
- exprs: Vec<ExprRef<H>>)
- -> Vec<Constant<H>>
- {
- exprs.into_iter().map(|expr| self.as_constant(expr)).collect()
- }
-
- fn named_field_constants(&mut self,
- field_names: Vec<Field<H>>,
- field_exprs: Vec<FieldExprRef<H>>)
- -> Vec<Constant<H>>
- {
- let fields_map: FnvHashMap<_, _> =
- field_exprs.into_iter()
- .map(|f| (f.name, self.as_constant(f.expr)))
- .collect();
-
- let fields: Vec<_> =
- field_names.into_iter()
- .map(|n| fields_map[&n].clone())
- .collect();
-
- fields
+ &format!("expression is not a valid constant {:?}", kind)),
+ }
}
}
use hair::*;
use repr::*;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Compile `expr`, yielding an lvalue that we can move from etc.
pub fn as_lvalue<M>(&mut self,
block: BasicBlock,
expr: M)
- -> BlockAnd<Lvalue<H>>
- where M: Mirror<H, Output=Expr<H>>
+ -> BlockAnd<Lvalue<'tcx>>
+ where M: Mirror<'tcx, Output=Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_lvalue(block, expr)
fn expr_as_lvalue(&mut self,
mut block: BasicBlock,
- expr: Expr<H>)
- -> BlockAnd<Lvalue<H>>
- {
- debug!("expr_as_lvalue(block={:?}, expr={:?})",
- block, expr);
+ expr: Expr<'tcx>)
+ -> BlockAnd<Lvalue<'tcx>> {
+ debug!("expr_as_lvalue(block={:?}, expr={:?})", block, expr);
let this = self;
let expr_span = expr.span;
match expr.kind {
ExprKind::Scope { extent, value } => {
- this.in_scope(extent, block, |this| {
- this.as_lvalue(block, value)
- })
- }
- ExprKind::Paren { arg } => {
- this.as_lvalue(block, arg)
+ this.in_scope(extent, block, |this| this.as_lvalue(block, value))
}
ExprKind::Field { lhs, name } => {
let lvalue = unpack!(block = this.as_lvalue(block, lhs));
idx.clone(),
Operand::Consume(len)));
- let (success, failure) = (this.cfg.start_new_block(),
- this.cfg.start_new_block());
+ let (success, failure) = (this.cfg.start_new_block(), this.cfg.start_new_block());
this.cfg.terminate(block,
Terminator::If {
cond: Operand::Consume(lt),
- targets: [success, failure]
+ targets: [success, failure],
});
this.panic(failure);
success.and(slice.index(idx))
use hair::*;
use repr::*;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Compile `expr` into a value that can be used as an operand.
/// If `expr` is an lvalue like `x`, this will introduce a
/// temporary `tmp = x`, so that we capture the value of `x` at
/// this time.
- pub fn as_operand<M>(&mut self,
- block: BasicBlock,
- expr: M)
- -> BlockAnd<Operand<H>>
- where M: Mirror<H, Output=Expr<H>>
+ pub fn as_operand<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Operand<'tcx>>
+ where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_operand(block, expr)
fn expr_as_operand(&mut self,
mut block: BasicBlock,
- expr: Expr<H>)
- -> BlockAnd<Operand<H>>
- {
- debug!("expr_as_operand(block={:?}, expr={:?})",
- block, expr);
+ expr: Expr<'tcx>)
+ -> BlockAnd<Operand<'tcx>> {
+ debug!("expr_as_operand(block={:?}, expr={:?})", block, expr);
let this = self;
- match expr.kind {
- ExprKind::Scope { extent, value } => {
- return this.in_scope(extent, block, |this| {
- this.as_operand(block, value)
- });
- }
- ExprKind::Paren { arg } => {
- return this.as_operand(block, arg);
- }
- _ => { }
+ if let ExprKind::Scope { extent, value } = expr.kind {
+ return this.in_scope(extent, block, |this| this.as_operand(block, value));
}
let category = Category::of(&expr.kind).unwrap();
use hair::*;
use repr::*;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Compile `expr`, yielding an rvalue.
- pub fn as_rvalue<M>(&mut self,
- block: BasicBlock,
- expr: M)
- -> BlockAnd<Rvalue<H>>
- where M: Mirror<H, Output=Expr<H>>
+ pub fn as_rvalue<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Rvalue<'tcx>>
+ where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_rvalue(block, expr)
fn expr_as_rvalue(&mut self,
mut block: BasicBlock,
- expr: Expr<H>)
- -> BlockAnd<Rvalue<H>>
- {
- debug!("expr_as_rvalue(block={:?}, expr={:?})",
- block, expr);
+ expr: Expr<'tcx>)
+ -> BlockAnd<Rvalue<'tcx>> {
+ debug!("expr_as_rvalue(block={:?}, expr={:?})", block, expr);
let this = self;
let expr_span = expr.span;
match expr.kind {
ExprKind::Scope { extent, value } => {
- this.in_scope(extent, block, |this| {
- this.as_rvalue(block, value)
- })
- }
- ExprKind::Paren { arg } => {
- this.as_rvalue(block, arg)
+ this.in_scope(extent, block, |this| this.as_rvalue(block, value))
}
ExprKind::InlineAsm { asm } => {
block.and(Rvalue::InlineAsm(asm))
let arg = unpack!(block = this.as_operand(block, arg));
block.and(Rvalue::UnaryOp(op, arg))
}
- ExprKind::Box { place: _, value } => {
+ ExprKind::Box { value } => {
let value = this.hir.mirror(value);
let value_ty = value.ty.clone();
let result = this.temp(value_ty.clone());
.map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr))))
.collect();
- let field_names =
- this.hir.fields(adt_def, variant_index);
+ let field_names = this.hir.fields(adt_def, variant_index);
- let base =
- base.map(|base| unpack!(block = this.as_lvalue(block, base)));
+ let base = base.map(|base| unpack!(block = this.as_lvalue(block, base)));
// for the actual values we use, take either the
// expr the user specified or, if they didn't
use hair::*;
use repr::*;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Compile `expr` into a fresh temporary. This is used when building
/// up rvalues so as to freeze the value that will be consumed.
- pub fn as_temp<M>(&mut self,
- block: BasicBlock,
- expr: M)
- -> BlockAnd<Lvalue<H>>
- where M: Mirror<H, Output=Expr<H>>
+ pub fn as_temp<M>(&mut self, block: BasicBlock, expr: M) -> BlockAnd<Lvalue<'tcx>>
+ where M: Mirror<'tcx, Output = Expr<'tcx>>
{
let expr = self.hir.mirror(expr);
self.expr_as_temp(block, expr)
}
- fn expr_as_temp(&mut self,
- mut block: BasicBlock,
- expr: Expr<H>)
- -> BlockAnd<Lvalue<H>>
- {
- debug!("expr_as_temp(block={:?}, expr={:?})",
- block, expr);
+ fn expr_as_temp(&mut self, mut block: BasicBlock, expr: Expr<'tcx>) -> BlockAnd<Lvalue<'tcx>> {
+ debug!("expr_as_temp(block={:?}, expr={:?})", block, expr);
let this = self;
- match expr.kind {
- ExprKind::Scope { extent, value } => {
- return this.in_scope(extent, block, |this| {
- this.as_temp(block, value)
- });
- }
- ExprKind::Paren { arg } => {
- return this.as_temp(block, arg);
- }
- _ => { }
+ if let ExprKind::Scope { extent, value } = expr.kind {
+ return this.in_scope(extent, block, |this| this.as_temp(block, value));
}
let expr_ty = expr.ty.clone();
let temp_lifetime = match expr.temp_lifetime {
Some(t) => t,
None => {
- this.hir.span_bug(
- expr.span,
- &format!("no temp_lifetime for expr"));
+ this.hir.span_bug(expr.span, &format!("no temp_lifetime for expr"));
}
};
this.schedule_drop(expr.span, temp_lifetime, DropKind::Deep, &temp, expr_ty);
/// Determines the category for a given expression. Note that scope
/// and paren expressions have no category.
impl Category {
- pub fn of<H:Hair>(ek: &ExprKind<H>) -> Option<Category> {
+ pub fn of<'tcx>(ek: &ExprKind<'tcx>) -> Option<Category> {
match *ek {
- ExprKind::Scope { .. } |
- ExprKind::Paren { .. } =>
- None,
+ ExprKind::Scope { .. } => None,
ExprKind::Field { .. } |
ExprKind::Deref { .. } |
use build::scope::LoopScope;
use hair::*;
use repr::*;
+use rustc::middle::region::CodeExtent;
+use syntax::codemap::Span;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized.
pub fn into_expr(&mut self,
- destination: &Lvalue<H>,
+ destination: &Lvalue<'tcx>,
mut block: BasicBlock,
- expr: Expr<H>)
+ expr: Expr<'tcx>)
-> BlockAnd<()>
{
debug!("into_expr(destination={:?}, block={:?}, expr={:?})",
match expr.kind {
ExprKind::Scope { extent, value } => {
- this.in_scope(extent, block, |this| {
- this.into(destination, block, value)
- })
- }
- ExprKind::Paren { arg } => {
- this.into(destination, block, arg)
+ this.in_scope(extent, block, |this| this.into(destination, block, value))
}
ExprKind::Block { body: ast_block } => {
this.ast_block(destination, block, ast_block)
true_block, expr_span, destination,
Constant {
span: expr_span,
- kind: ConstantKind::Literal(Literal::Bool { value: true }),
+ ty: this.hir.bool_ty(),
+ literal: this.hir.true_literal(),
});
this.cfg.push_assign_constant(
false_block, expr_span, destination,
Constant {
span: expr_span,
- kind: ConstantKind::Literal(Literal::Bool { value: false }),
+ ty: this.hir.bool_ty(),
+ literal: this.hir.false_literal(),
});
this.cfg.terminate(true_block, Terminator::Goto { target: join_block });
|loop_scope| loop_scope.continue_block)
}
ExprKind::Break { label } => {
- this.break_or_continue(expr_span, label, block,
- |loop_scope| loop_scope.break_block)
+ this.break_or_continue(expr_span, label, block, |loop_scope| loop_scope.break_block)
}
ExprKind::Return { value } => {
unpack!(block = this.into(&Lvalue::ReturnPointer, block, value));
data: CallData {
destination: destination.clone(),
func: fun,
- args: args
+ args: args,
},
- targets: [success, panic]
+ targets: [success, panic],
});
success.unit()
}
}
fn break_or_continue<F>(&mut self,
- span: H::Span,
- label: Option<H::CodeExtent>,
+ span: Span,
+ label: Option<CodeExtent>,
block: BasicBlock,
exit_selector: F)
-> BlockAnd<()>
- where F: FnOnce(&LoopScope<H>) -> BasicBlock
+ where F: FnOnce(&LoopScope) -> BasicBlock
{
let loop_scope = self.find_loop_scope(span, label);
let exit_block = exit_selector(&loop_scope);
use hair::*;
use repr::*;
-pub trait EvalInto<H:Hair> {
- fn eval_into(self, builder: &mut Builder<H>, destination: &Lvalue<H>,
- block: BasicBlock) -> BlockAnd<()>;
+pub trait EvalInto<'tcx> {
+ fn eval_into<'a>(self,
+ builder: &mut Builder<'a, 'tcx>,
+ destination: &Lvalue<'tcx>,
+ block: BasicBlock)
+ -> BlockAnd<()>;
}
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
pub fn into<E>(&mut self,
- destination: &Lvalue<H>,
+ destination: &Lvalue<'tcx>,
block: BasicBlock,
expr: E)
-> BlockAnd<()>
- where E: EvalInto<H>
+ where E: EvalInto<'tcx>
{
expr.eval_into(self, destination, block)
}
}
-impl<H:Hair> EvalInto<H> for ExprRef<H> {
- fn eval_into(self,
- builder: &mut Builder<H>,
- destination: &Lvalue<H>,
- block: BasicBlock)
- -> BlockAnd<()> {
+impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
+ fn eval_into<'a>(self,
+ builder: &mut Builder<'a, 'tcx>,
+ destination: &Lvalue<'tcx>,
+ block: BasicBlock)
+ -> BlockAnd<()> {
let expr = builder.hir.mirror(self);
builder.into_expr(destination, block, expr)
}
}
-impl<H:Hair> EvalInto<H> for Expr<H> {
- fn eval_into(self,
- builder: &mut Builder<H>,
- destination: &Lvalue<H>,
- block: BasicBlock)
- -> BlockAnd<()> {
+impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
+ fn eval_into<'a>(self,
+ builder: &mut Builder<'a, 'tcx>,
+ destination: &Lvalue<'tcx>,
+ block: BasicBlock)
+ -> BlockAnd<()> {
builder.into_expr(destination, block, self)
}
}
-impl<H:Hair> EvalInto<H> for Option<ExprRef<H>> {
- fn eval_into(self,
- builder: &mut Builder<H>,
- destination: &Lvalue<H>,
- block: BasicBlock)
- -> BlockAnd<()> {
+impl<'tcx> EvalInto<'tcx> for Option<ExprRef<'tcx>> {
+ fn eval_into<'a>(self,
+ builder: &mut Builder<'a, 'tcx>,
+ destination: &Lvalue<'tcx>,
+ block: BasicBlock)
+ -> BlockAnd<()> {
match self {
Some(expr) => builder.into(destination, block, expr),
- None => block.unit()
+ None => block.unit(),
}
}
}
use build::{BlockAnd, Builder};
use repr::*;
+use rustc::middle::region::CodeExtent;
+use rustc::middle::ty::{AdtDef, Ty};
use hair::*;
+use syntax::ast::{Name, NodeId};
+use syntax::codemap::Span;
// helper functions, broken out by category:
mod simplify;
mod test;
mod util;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
pub fn match_expr(&mut self,
- destination: &Lvalue<H>,
- span: H::Span,
+ destination: &Lvalue<'tcx>,
+ span: Span,
mut block: BasicBlock,
- discriminant: ExprRef<H>,
- arms: Vec<Arm<H>>)
- -> BlockAnd<()>
- {
- let discriminant_lvalue =
- unpack!(block = self.as_lvalue(block, discriminant));
+ discriminant: ExprRef<'tcx>,
+ arms: Vec<Arm<'tcx>>)
+ -> BlockAnd<()> {
+ let discriminant_lvalue = unpack!(block = self.as_lvalue(block, discriminant));
+
+ // Before we do anything, create uninitialized variables with
+ // suitable extent for all of the bindings in this match. It's
+ // easiest to do this up front because some of these arms may
+ // be unreachable or reachable multiple times.
+ let var_extent = self.extent_of_innermost_scope().unwrap();
+ for arm in &arms {
+ self.declare_bindings(var_extent, arm.patterns[0].clone());
+ }
- let arm_blocks: Vec<BasicBlock> =
- arms.iter()
- .map(|_| self.cfg.start_new_block())
- .collect();
+ let mut arm_blocks = ArmBlocks {
+ blocks: arms.iter()
+ .map(|_| self.cfg.start_new_block())
+ .collect(),
+ };
- let arm_bodies: Vec<ExprRef<H>> =
+ let arm_bodies: Vec<ExprRef<'tcx>> =
arms.iter()
.map(|arm| arm.body.clone())
.collect();
// highest priority candidate comes last in the list. This the
// reverse of the order in which candidates are written in the
// source.
- let candidates: Vec<Candidate<H>> =
- arms.into_iter()
- .zip(arm_blocks.iter())
+ let candidates: Vec<Candidate<'tcx>> =
+ arms.iter()
+ .enumerate()
.rev() // highest priority comes last
- .flat_map(|(arm, &arm_block)| {
- let guard = arm.guard;
- arm.patterns.into_iter()
+ .flat_map(|(arm_index, arm)| {
+ arm.patterns.iter()
.rev()
- .map(move |pat| (arm_block, pat, guard.clone()))
+ .map(move |pat| (arm_index, pat.clone(), arm.guard.clone()))
})
- .map(|(arm_block, pattern, guard)| {
+ .map(|(arm_index, pattern, guard)| {
Candidate {
match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)],
bindings: vec![],
guard: guard,
- arm_block: arm_block,
+ arm_index: arm_index,
}
})
.collect();
// this will generate code to test discriminant_lvalue and
// branch to the appropriate arm block
- let var_extent = self.extent_of_innermost_scope().unwrap();
- self.match_candidates(span, var_extent, candidates, block);
+ self.match_candidates(span, &mut arm_blocks, candidates, block);
// all the arm blocks will rejoin here
let end_block = self.cfg.start_new_block();
- for (arm_body, &arm_block) in arm_bodies.into_iter().zip(arm_blocks.iter()) {
- let mut arm_block = arm_block;
+ for (arm_index, arm_body) in arm_bodies.into_iter().enumerate() {
+ let mut arm_block = arm_blocks.blocks[arm_index];
unpack!(arm_block = self.into(destination, arm_block, arm_body));
self.cfg.terminate(arm_block, Terminator::Goto { target: end_block });
}
pub fn expr_into_pattern(&mut self,
mut block: BasicBlock,
- var_extent: H::CodeExtent, // lifetime of vars
- irrefutable_pat: PatternRef<H>,
- initializer: ExprRef<H>)
- -> BlockAnd<()>
- {
+ var_extent: CodeExtent, // lifetime of vars
+ irrefutable_pat: PatternRef<'tcx>,
+ initializer: ExprRef<'tcx>)
+ -> BlockAnd<()> {
// optimize the case of `let x = ...`
let irrefutable_pat = self.hir.mirror(irrefutable_pat);
match irrefutable_pat.kind {
var,
ty,
subpattern: None } => {
- let index = self.declare_binding(var_extent, mutability, name,
- var, ty, irrefutable_pat.span);
+ let index = self.declare_binding(var_extent,
+ mutability,
+ name,
+ var,
+ ty,
+ irrefutable_pat.span);
let lvalue = Lvalue::Var(index);
return self.into(&lvalue, block, initializer);
}
- _ => { }
+ _ => {}
}
let lvalue = unpack!(block = self.as_lvalue(block, initializer));
- self.lvalue_into_pattern(block, var_extent,
- PatternRef::Mirror(Box::new(irrefutable_pat)), &lvalue)
+ self.lvalue_into_pattern(block,
+ var_extent,
+ PatternRef::Mirror(Box::new(irrefutable_pat)),
+ &lvalue)
}
pub fn lvalue_into_pattern(&mut self,
mut block: BasicBlock,
- var_extent: H::CodeExtent,
- irrefutable_pat: PatternRef<H>,
- initializer: &Lvalue<H>)
- -> BlockAnd<()>
- {
+ var_extent: CodeExtent,
+ irrefutable_pat: PatternRef<'tcx>,
+ initializer: &Lvalue<'tcx>)
+ -> BlockAnd<()> {
+ // first, creating the bindings
+ self.declare_bindings(var_extent, irrefutable_pat.clone());
+
// create a dummy candidate
- let mut candidate = Candidate::<H> {
- match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat)],
+ let mut candidate = Candidate::<'tcx> {
+ match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())],
bindings: vec![],
guard: None,
- arm_block: block
+ arm_index: 0, // since we don't call `match_candidates`, this field is unused
};
// Simplify the candidate. Since the pattern is irrefutable, this should
unpack!(block = self.simplify_candidate(block, &mut candidate));
if !candidate.match_pairs.is_empty() {
- self.hir.span_bug(
- candidate.match_pairs[0].pattern.span,
- &format!("match pairs {:?} remaining after simplifying irrefutable pattern",
- candidate.match_pairs));
+ self.hir.span_bug(candidate.match_pairs[0].pattern.span,
+ &format!("match pairs {:?} remaining after simplifying \
+ irrefutable pattern",
+ candidate.match_pairs));
}
// now apply the bindings, which will also declare the variables
- self.bind_matched_candidate(block, var_extent, candidate.bindings);
+ self.bind_matched_candidate(block, candidate.bindings);
block.unit()
}
- pub fn declare_uninitialized_variables(&mut self,
- var_extent: H::CodeExtent,
- pattern: PatternRef<H>)
- {
+ pub fn declare_bindings(&mut self, var_extent: CodeExtent, pattern: PatternRef<'tcx>) {
let pattern = self.hir.mirror(pattern);
match pattern.kind {
PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => {
self.declare_binding(var_extent, mutability, name, var, ty, pattern.span);
if let Some(subpattern) = subpattern {
- self.declare_uninitialized_variables(var_extent, subpattern);
+ self.declare_bindings(var_extent, subpattern);
}
}
PatternKind::Array { prefix, slice, suffix } |
PatternKind::Slice { prefix, slice, suffix } => {
for subpattern in prefix.into_iter().chain(slice).chain(suffix) {
- self.declare_uninitialized_variables(var_extent, subpattern);
+ self.declare_bindings(var_extent, subpattern);
}
}
- PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
- }
+ PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
PatternKind::Deref { subpattern } => {
- self.declare_uninitialized_variables(var_extent, subpattern);
+ self.declare_bindings(var_extent, subpattern);
}
PatternKind::Leaf { subpatterns } |
PatternKind::Variant { subpatterns, .. } => {
for subpattern in subpatterns {
- self.declare_uninitialized_variables(var_extent, subpattern.pattern);
+ self.declare_bindings(var_extent, subpattern.pattern);
}
}
}
}
}
+/// List of blocks for each arm (and potentially other metadata in the
+/// future).
+struct ArmBlocks {
+ blocks: Vec<BasicBlock>,
+}
+
#[derive(Clone, Debug)]
-struct Candidate<H:Hair> {
+struct Candidate<'tcx> {
// all of these must be satisfied...
- match_pairs: Vec<MatchPair<H>>,
+ match_pairs: Vec<MatchPair<'tcx>>,
// ...these bindings established...
- bindings: Vec<Binding<H>>,
+ bindings: Vec<Binding<'tcx>>,
// ...and the guard must be evaluated...
- guard: Option<ExprRef<H>>,
+ guard: Option<ExprRef<'tcx>>,
- // ...and then we branch here.
- arm_block: BasicBlock,
+ // ...and then we branch to arm with this index.
+ arm_index: usize,
}
#[derive(Clone, Debug)]
-struct Binding<H:Hair> {
- span: H::Span,
- source: Lvalue<H>,
- name: H::Ident,
- var_id: H::VarId,
- var_ty: H::Ty,
+struct Binding<'tcx> {
+ span: Span,
+ source: Lvalue<'tcx>,
+ name: Name,
+ var_id: NodeId,
+ var_ty: Ty<'tcx>,
mutability: Mutability,
- binding_mode: BindingMode<H>,
+ binding_mode: BindingMode,
}
#[derive(Clone, Debug)]
-struct MatchPair<H:Hair> {
+struct MatchPair<'tcx> {
// this lvalue...
- lvalue: Lvalue<H>,
+ lvalue: Lvalue<'tcx>,
// ... must match this pattern.
- pattern: Pattern<H>,
+ pattern: Pattern<'tcx>,
}
#[derive(Clone, Debug, PartialEq)]
-enum TestKind<H:Hair> {
+enum TestKind<'tcx> {
// test the branches of enum
- Switch { adt_def: H::AdtDef },
+ Switch {
+ adt_def: AdtDef<'tcx>,
+ },
// test for equality
- Eq { value: Constant<H>, ty: H::Ty },
+ Eq {
+ value: Literal<'tcx>,
+ ty: Ty<'tcx>,
+ },
// test whether the value falls within an inclusive range
- Range { lo: Constant<H>, hi: Constant<H>, ty: H::Ty },
+ Range {
+ lo: Literal<'tcx>,
+ hi: Literal<'tcx>,
+ ty: Ty<'tcx>,
+ },
// test length of the slice is equal to len
- Len { len: usize, op: BinOp },
+ Len {
+ len: usize,
+ op: BinOp,
+ },
}
#[derive(Debug)]
-struct Test<H:Hair> {
- span: H::Span,
- kind: TestKind<H>,
+struct Test<'tcx> {
+ span: Span,
+ kind: TestKind<'tcx>,
}
///////////////////////////////////////////////////////////////////////////
// Main matching algorithm
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
fn match_candidates(&mut self,
- span: H::Span,
- var_extent: H::CodeExtent,
- mut candidates: Vec<Candidate<H>>,
+ span: Span,
+ arm_blocks: &mut ArmBlocks,
+ mut candidates: Vec<Candidate<'tcx>>,
mut block: BasicBlock)
{
- debug!("matched_candidate(span={:?}, var_extent={:?}, block={:?}, candidates={:?})",
- span, var_extent, block, candidates);
+ debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
+ span, block, candidates);
// Start by simplifying candidates. Once this process is
// complete, all the match pairs which remain require some
// If so, apply any bindings, test the guard (if any), and
// branch to the arm.
let candidate = candidates.pop().unwrap();
- match self.bind_and_guard_matched_candidate(block, var_extent, candidate) {
- None => { return; }
- Some(b) => { block = b; }
+ if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) {
+ block = b;
+ } else {
+ // if None is returned, then any remaining candidates
+ // are unreachable (at least not through this path).
+ return;
}
}
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
for (outcome, mut target_block) in target_blocks.into_iter().enumerate() {
- let applicable_candidates: Vec<Candidate<H>> =
+ let applicable_candidates: Vec<Candidate<'tcx>> =
candidates.iter()
.filter_map(|candidate| {
unpack!(target_block =
candidate))
})
.collect();
- self.match_candidates(span, var_extent, applicable_candidates, target_block);
+ self.match_candidates(span, arm_blocks, applicable_candidates, target_block);
}
}
/// MIR).
fn bind_and_guard_matched_candidate(&mut self,
mut block: BasicBlock,
- var_extent: H::CodeExtent,
- candidate: Candidate<H>)
+ arm_blocks: &mut ArmBlocks,
+ candidate: Candidate<'tcx>)
-> Option<BasicBlock> {
- debug!("bind_and_guard_matched_candidate(block={:?}, var_extent={:?}, candidate={:?})",
- block, var_extent, candidate);
+ debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
+ block, candidate);
debug_assert!(candidate.match_pairs.is_empty());
- self.bind_matched_candidate(block, var_extent, candidate.bindings);
+ self.bind_matched_candidate(block, candidate.bindings);
+
+ let arm_block = arm_blocks.blocks[candidate.arm_index];
if let Some(guard) = candidate.guard {
// the block to branch to if the guard fails; if there is no
let cond = unpack!(block = self.as_operand(block, guard));
let otherwise = self.cfg.start_new_block();
self.cfg.terminate(block, Terminator::If { cond: cond,
- targets: [candidate.arm_block, otherwise]});
+ targets: [arm_block, otherwise]});
Some(otherwise)
} else {
- self.cfg.terminate(block, Terminator::Goto { target: candidate.arm_block });
+ self.cfg.terminate(block, Terminator::Goto { target: arm_block });
None
}
}
fn bind_matched_candidate(&mut self,
block: BasicBlock,
- var_extent: H::CodeExtent,
- bindings: Vec<Binding<H>>) {
- debug!("bind_matched_candidate(block={:?}, var_extent={:?}, bindings={:?})",
- block, var_extent, bindings);
+ bindings: Vec<Binding<'tcx>>) {
+ debug!("bind_matched_candidate(block={:?}, bindings={:?})",
+ block, bindings);
// Assign each of the bindings. This may trigger moves out of the candidate.
for binding in bindings {
- // Create a variable for the `var_id` being bound. In the
- // case where there are multiple patterns for a single
- // arm, it may already exist.
- let var_index = if !self.var_indices.contains_key(&binding.var_id) {
- self.declare_binding(var_extent,
- binding.mutability,
- binding.name,
- binding.var_id,
- binding.var_ty,
- binding.span)
- } else {
- self.var_indices[&binding.var_id]
- };
+ // Find the variable for the `var_id` being bound. It
+ // should have been created by a previous call to
+ // `declare_bindings`.
+ let var_index = self.var_indices[&binding.var_id];
let rvalue = match binding.binding_mode {
BindingMode::ByValue =>
}
fn declare_binding(&mut self,
- var_extent: H::CodeExtent,
+ var_extent: CodeExtent,
mutability: Mutability,
- name: H::Ident,
- var_id: H::VarId,
- var_ty: H::Ty,
- span: H::Span)
+ name: Name,
+ var_id: NodeId,
+ var_ty: Ty<'tcx>,
+ span: Span)
-> u32
{
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_extent={:?}, span={:?})",
var_id, name, var_ty, var_extent, span);
let index = self.var_decls.len();
- self.var_decls.push(VarDecl::<H> {
+ self.var_decls.push(VarDecl::<'tcx> {
mutability: mutability,
name: name,
ty: var_ty.clone(),
index
}
}
-
use std::mem;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
pub fn simplify_candidate(&mut self,
mut block: BasicBlock,
- candidate: &mut Candidate<H>)
- -> BlockAnd<()>
- {
+ candidate: &mut Candidate<'tcx>)
+ -> BlockAnd<()> {
// repeatedly simplify match pairs until fixed point is reached
loop {
let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
let mut progress = match_pairs.len(); // count how many were simplified
for match_pair in match_pairs {
match self.simplify_match_pair(block, match_pair, candidate) {
- Ok(b) => { block = b; }
+ Ok(b) => {
+ block = b;
+ }
Err(match_pair) => {
candidate.match_pairs.push(match_pair);
progress -= 1; // this one was not simplified
/// Tries to simplify `match_pair`, returning true if
/// successful. If successful, new match pairs and bindings will
- /// have been pushed into the candidate. On failure (if false is
- /// returned), no changes are made to candidate.
+ /// have been pushed into the candidate. If no simplification is
+ /// possible, Err is returned and no changes are made to
+ /// candidate.
fn simplify_match_pair(&mut self,
mut block: BasicBlock,
- match_pair: MatchPair<H>,
- candidate: &mut Candidate<H>)
- -> Result<BasicBlock, MatchPair<H>> // returns Err() if cannot simplify
- {
+ match_pair: MatchPair<'tcx>,
+ candidate: &mut Candidate<'tcx>)
+ -> Result<BasicBlock, MatchPair<'tcx>> {
match match_pair.pattern.kind {
PatternKind::Wild(..) => {
// nothing left to do
PatternKind::Leaf { subpatterns } => {
// tuple struct, match subpats (if any)
- candidate.match_pairs.extend(
- self.field_match_pairs(match_pair.lvalue, subpatterns));
+ candidate.match_pairs
+ .extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
Ok(block)
}
}
}
}
-
use build::matches::{Candidate, MatchPair, Test, TestKind};
use hair::*;
use repr::*;
+use syntax::codemap::Span;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Identifies what test is needed to decide if `match_pair` is applicable.
///
/// It is a bug to call this with a simplifyable pattern.
- pub fn test(&mut self, match_pair: &MatchPair<H>) -> Test<H> {
+ pub fn test(&mut self, match_pair: &MatchPair<'tcx>) -> Test<'tcx> {
match match_pair.pattern.kind {
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
Test {
}
}
- PatternKind::Constant { ref expr } => {
- let expr = self.as_constant(expr.clone());
+ PatternKind::Constant { ref value } => {
Test {
span: match_pair.pattern.span,
- kind: TestKind::Eq { value: expr, ty: match_pair.pattern.ty.clone() },
+ kind: TestKind::Eq {
+ value: value.clone(),
+ ty: match_pair.pattern.ty.clone(),
+ },
}
}
PatternKind::Range { ref lo, ref hi } => {
- let lo = self.as_constant(lo.clone());
- let hi = self.as_constant(hi.clone());
Test {
span: match_pair.pattern.span,
- kind: TestKind::Range { lo: lo, hi: hi, ty: match_pair.pattern.ty.clone() },
+ kind: TestKind::Range {
+ lo: lo.clone(),
+ hi: hi.clone(),
+ ty: match_pair.pattern.ty.clone(),
+ },
}
}
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
let len = prefix.len() + suffix.len();
- let op = if slice.is_some() {BinOp::Ge} else {BinOp::Eq};
+ let op = if slice.is_some() {
+ BinOp::Ge
+ } else {
+ BinOp::Eq
+ };
Test {
span: match_pair.pattern.span,
kind: TestKind::Len { len: len, op: op },
/// Generates the code to perform a test.
pub fn perform_test(&mut self,
block: BasicBlock,
- lvalue: &Lvalue<H>,
- test: &Test<H>)
+ lvalue: &Lvalue<'tcx>,
+ test: &Test<'tcx>)
-> Vec<BasicBlock> {
match test.kind.clone() {
TestKind::Switch { adt_def } => {
TestKind::Eq { value, ty } => {
// call PartialEq::eq(discrim, constant)
- let constant = self.push_constant(block, test.span, ty.clone(), value);
+ let constant = self.push_literal(block, test.span, ty.clone(), value);
let item_ref = self.hir.partial_eq(ty);
self.call_comparison_fn(block, test.span, item_ref, lvalue.clone(), constant)
}
TestKind::Range { lo, hi, ty } => {
// Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`.
- let lo = self.push_constant(block, test.span, ty.clone(), lo);
- let hi = self.push_constant(block, test.span, ty.clone(), hi);
+ let lo = self.push_literal(block, test.span, ty.clone(), lo);
+ let hi = self.push_literal(block, test.span, ty.clone(), hi);
let item_ref = self.hir.partial_le(ty);
- let lo_blocks =
- self.call_comparison_fn(block, test.span, item_ref.clone(), lo, lvalue.clone());
+ let lo_blocks = self.call_comparison_fn(block,
+ test.span,
+ item_ref.clone(),
+ lo,
+ lvalue.clone());
- let hi_blocks =
- self.call_comparison_fn(lo_blocks[0], test.span, item_ref, lvalue.clone(), hi);
+ let hi_blocks = self.call_comparison_fn(lo_blocks[0],
+ test.span,
+ item_ref,
+ lvalue.clone(),
+ hi);
let failure = self.cfg.start_new_block();
self.cfg.terminate(lo_blocks[1], Terminator::Goto { target: failure });
let (actual, result) = (self.temp(usize_ty), self.temp(bool_ty));
// actual = len(lvalue)
- self.cfg.push_assign(
- block, test.span,
- &actual, Rvalue::Len(lvalue.clone()));
+ self.cfg.push_assign(block, test.span, &actual, Rvalue::Len(lvalue.clone()));
// expected = <N>
- let expected =
- self.push_usize(block, test.span, len);
+ let expected = self.push_usize(block, test.span, len);
// result = actual == expected OR result = actual < expected
- self.cfg.push_assign(
- block, test.span,
- &result, Rvalue::BinaryOp(op,
- Operand::Consume(actual),
- Operand::Consume(expected)));
+ self.cfg.push_assign(block,
+ test.span,
+ &result,
+ Rvalue::BinaryOp(op,
+ Operand::Consume(actual),
+ Operand::Consume(expected)));
// branch based on result
let target_blocks: Vec<_> = vec![self.cfg.start_new_block(),
fn call_comparison_fn(&mut self,
block: BasicBlock,
- span: H::Span,
- item_ref: ItemRef<H>,
- lvalue1: Lvalue<H>,
- lvalue2: Lvalue<H>)
+ span: Span,
+ item_ref: ItemRef<'tcx>,
+ lvalue1: Lvalue<'tcx>,
+ lvalue2: Lvalue<'tcx>)
-> Vec<BasicBlock> {
- let target_blocks = vec![self.cfg.start_new_block(),
- self.cfg.start_new_block()];
+ let target_blocks = vec![self.cfg.start_new_block(), self.cfg.start_new_block()];
let bool_ty = self.hir.bool_ty();
let eq_result = self.temp(bool_ty);
self.cfg.terminate(call_blocks[0],
Terminator::If {
cond: Operand::Consume(eq_result),
- targets: [target_blocks[0], target_blocks[1]]
+ targets: [target_blocks[0], target_blocks[1]],
});
target_blocks
/// @ 22])`.
pub fn candidate_under_assumption(&mut self,
mut block: BasicBlock,
- test_lvalue: &Lvalue<H>,
- test_kind: &TestKind<H>,
+ test_lvalue: &Lvalue<'tcx>,
+ test_kind: &TestKind<'tcx>,
test_outcome: usize,
- candidate: &Candidate<H>)
- -> BlockAnd<Option<Candidate<H>>> {
+ candidate: &Candidate<'tcx>)
+ -> BlockAnd<Option<Candidate<'tcx>>> {
let candidate = candidate.clone();
let match_pairs = candidate.match_pairs;
let result = unpack!(block = self.match_pairs_under_assumption(block,
match_pairs));
block.and(match result {
Some(match_pairs) => Some(Candidate { match_pairs: match_pairs, ..candidate }),
- None => None
+ None => None,
})
}
/// work of transforming the list of match pairs.
fn match_pairs_under_assumption(&mut self,
mut block: BasicBlock,
- test_lvalue: &Lvalue<H>,
- test_kind: &TestKind<H>,
+ test_lvalue: &Lvalue<'tcx>,
+ test_kind: &TestKind<'tcx>,
test_outcome: usize,
- match_pairs: Vec<MatchPair<H>>)
- -> BlockAnd<Option<Vec<MatchPair<H>>>> {
+ match_pairs: Vec<MatchPair<'tcx>>)
+ -> BlockAnd<Option<Vec<MatchPair<'tcx>>>> {
let mut result = vec![];
for match_pair in match_pairs {
/// It is a bug to call this with a simplifyable pattern.
pub fn consequent_match_pairs_under_assumption(&mut self,
mut block: BasicBlock,
- match_pair: MatchPair<H>,
+ match_pair: MatchPair<'tcx>,
test_outcome: usize)
- -> BlockAnd<Option<Vec<MatchPair<H>>>> {
+ -> BlockAnd<Option<Vec<MatchPair<'tcx>>>> {
match match_pair.pattern.kind {
PatternKind::Variant { adt_def, variant_index, subpatterns } => {
if test_outcome != variant_index {
}
}
- fn error_simplifyable(&mut self, match_pair: &MatchPair<H>) -> ! {
- self.hir.span_bug(
- match_pair.pattern.span,
- &format!("simplifyable pattern found: {:?}", match_pair.pattern))
+ fn error_simplifyable(&mut self, match_pair: &MatchPair<'tcx>) -> ! {
+ self.hir.span_bug(match_pair.pattern.span,
+ &format!("simplifyable pattern found: {:?}", match_pair.pattern))
}
}
use repr::*;
use std::u32;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
pub fn field_match_pairs(&mut self,
- lvalue: Lvalue<H>,
- subpatterns: Vec<FieldPatternRef<H>>)
- -> Vec<MatchPair<H>> {
+ lvalue: Lvalue<'tcx>,
+ subpatterns: Vec<FieldPatternRef<'tcx>>)
+ -> Vec<MatchPair<'tcx>> {
subpatterns.into_iter()
.map(|fieldpat| {
let lvalue = lvalue.clone().field(fieldpat.field);
.collect()
}
- pub fn match_pair(&mut self, lvalue: Lvalue<H>, pattern: PatternRef<H>) -> MatchPair<H> {
+ pub fn match_pair(&mut self,
+ lvalue: Lvalue<'tcx>,
+ pattern: PatternRef<'tcx>)
+ -> MatchPair<'tcx> {
let pattern = self.hir.mirror(pattern);
MatchPair::new(lvalue, pattern)
}
///
/// and creates a match pair `tmp0 @ s`
pub fn prefix_suffix_slice(&mut self,
- match_pairs: &mut Vec<MatchPair<H>>,
+ match_pairs: &mut Vec<MatchPair<'tcx>>,
block: BasicBlock,
- lvalue: Lvalue<H>,
- prefix: Vec<PatternRef<H>>,
- opt_slice: Option<PatternRef<H>>,
- suffix: Vec<PatternRef<H>>)
- -> BlockAnd<()>
- {
+ lvalue: Lvalue<'tcx>,
+ prefix: Vec<PatternRef<'tcx>>,
+ opt_slice: Option<PatternRef<'tcx>>,
+ suffix: Vec<PatternRef<'tcx>>)
+ -> BlockAnd<()> {
// If there is a `..P` pattern, create a temporary `t0` for
// the slice and then a match pair `t0 @ P`:
if let Some(slice) = opt_slice {
let slice = self.hir.mirror(slice);
let prefix_len = prefix.len();
let suffix_len = suffix.len();
- let rvalue = Rvalue::Slice { input: lvalue.clone(),
- from_start: prefix_len,
- from_end: suffix_len };
+ let rvalue = Rvalue::Slice {
+ input: lvalue.clone(),
+ from_start: prefix_len,
+ from_end: suffix_len,
+ };
let temp = self.temp(slice.ty.clone()); // no need to schedule drop, temp is always copy
self.cfg.push_assign(block, slice.span, &temp, rvalue);
match_pairs.push(MatchPair::new(temp, slice));
/// Helper for `prefix_suffix_slice` which just processes the prefix and suffix.
fn prefix_suffix(&mut self,
- match_pairs: &mut Vec<MatchPair<H>>,
- lvalue: Lvalue<H>,
- prefix: Vec<PatternRef<H>>,
- suffix: Vec<PatternRef<H>>)
- {
+ match_pairs: &mut Vec<MatchPair<'tcx>>,
+ lvalue: Lvalue<'tcx>,
+ prefix: Vec<PatternRef<'tcx>>,
+ suffix: Vec<PatternRef<'tcx>>) {
let min_length = prefix.len() + suffix.len();
assert!(min_length < u32::MAX as usize);
let min_length = min_length as u32;
}
}
-impl<H:Hair> MatchPair<H> {
- pub fn new(lvalue: Lvalue<H>, pattern: Pattern<H>) -> MatchPair<H> {
- MatchPair { lvalue: lvalue, pattern: pattern }
+impl<'tcx> MatchPair<'tcx> {
+ pub fn new(lvalue: Lvalue<'tcx>, pattern: Pattern<'tcx>) -> MatchPair<'tcx> {
+ MatchPair {
+ lvalue: lvalue,
+ pattern: pattern,
+ }
}
}
use build::Builder;
use hair::*;
use repr::*;
-
+use rustc::middle::ty::Ty;
use std::u32;
+use syntax::codemap::Span;
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Add a new temporary value of type `ty` storing the result of
/// evaluating `expr`.
///
/// NB: **No cleanup is scheduled for this temporary.** You should
/// call `schedule_drop` once the temporary is initialized.
- pub fn temp(&mut self, ty: H::Ty) -> Lvalue<H> {
+ pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
let index = self.temp_decls.len();
self.temp_decls.push(TempDecl { ty: ty });
assert!(index < (u32::MAX) as usize);
lvalue
}
- pub fn push_constant(&mut self,
- block: BasicBlock,
- span: H::Span,
- ty: H::Ty,
- constant: Constant<H>)
- -> Lvalue<H> {
- let temp = self.temp(ty);
+ pub fn push_literal(&mut self,
+ block: BasicBlock,
+ span: Span,
+ ty: Ty<'tcx>,
+ literal: Literal<'tcx>)
+ -> Lvalue<'tcx> {
+ let temp = self.temp(ty.clone());
+ let constant = Constant {
+ span: span,
+ ty: ty,
+ literal: literal,
+ };
self.cfg.push_assign_constant(block, span, &temp, constant);
temp
}
- pub fn push_usize(&mut self,
- block: BasicBlock,
- span: H::Span,
- value: usize)
- -> Lvalue<H> {
+ pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> {
let usize_ty = self.hir.usize_ty();
let temp = self.temp(usize_ty);
self.cfg.push_assign_constant(
block, span, &temp,
Constant {
span: span,
- kind: ConstantKind::Literal(Literal::Uint { bits: IntegralBits::BSize,
- value: value as u64 }),
+ ty: self.hir.usize_ty(),
+ literal: self.hir.usize_literal(value),
});
temp
}
pub fn push_item_ref(&mut self,
block: BasicBlock,
- span: H::Span,
- item_ref: ItemRef<H>)
- -> Lvalue<H> {
- let constant = Constant {
- span: span,
- kind: ConstantKind::Literal(Literal::Item {
- def_id: item_ref.def_id,
- substs: item_ref.substs
- })
+ span: Span,
+ item_ref: ItemRef<'tcx>)
+ -> Lvalue<'tcx> {
+ let literal = Literal::Item {
+ def_id: item_ref.def_id,
+ substs: item_ref.substs,
};
- self.push_constant(block, span, item_ref.ty, constant)
+ self.push_literal(block, span, item_ref.ty, literal)
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use hair::{self, Hair};
+use hair;
+use rustc::middle::region::CodeExtent;
+use rustc::middle::ty::Ty;
use rustc_data_structures::fnv::FnvHashMap;
+use rustc_front::hir;
use repr::*;
-
-struct Builder<H:Hair> {
- hir: H,
- extents: FnvHashMap<H::CodeExtent, Vec<GraphExtent>>,
- cfg: CFG<H>,
- scopes: Vec<scope::Scope<H>>,
- loop_scopes: Vec<scope::LoopScope<H>>,
- unit_temp: Lvalue<H>,
- var_decls: Vec<VarDecl<H>>,
- var_indices: FnvHashMap<H::VarId, u32>,
- temp_decls: Vec<TempDecl<H>>,
+use syntax::ast;
+use syntax::codemap::Span;
+use tcx::{Cx, PatNode};
+
+struct Builder<'a, 'tcx: 'a> {
+ hir: Cx<'a, 'tcx>,
+ extents: FnvHashMap<CodeExtent, Vec<GraphExtent>>,
+ cfg: CFG<'tcx>,
+ scopes: Vec<scope::Scope<'tcx>>,
+ loop_scopes: Vec<scope::LoopScope>,
+ unit_temp: Lvalue<'tcx>,
+ var_decls: Vec<VarDecl<'tcx>>,
+ var_indices: FnvHashMap<ast::NodeId, u32>,
+ temp_decls: Vec<TempDecl<'tcx>>,
}
-struct CFG<H:Hair> {
- basic_blocks: Vec<BasicBlockData<H>>
+struct CFG<'tcx> {
+ basic_blocks: Vec<BasicBlockData<'tcx>>,
}
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// construct() -- the main entry point for building MIR for a function
-pub fn construct<H:Hair>(mut hir: H,
- _span: H::Span,
- implicit_arguments: Vec<H::Ty>,
- explicit_arguments: Vec<(H::Ty, H::Pattern)>,
- argument_extent: H::CodeExtent,
- ast_block: H::Block)
- -> Mir<H> {
+pub fn construct<'a, 'tcx>(mut hir: Cx<'a, 'tcx>,
+ _span: Span,
+ implicit_arguments: Vec<Ty<'tcx>>,
+ explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
+ argument_extent: CodeExtent,
+ ast_block: &'tcx hir::Block)
+ -> Mir<'tcx> {
let cfg = CFG { basic_blocks: vec![] };
// it's handy to have a temporary of type `()` sometimes, so make
// one from the start and keep it available
- let temp_decls = vec![TempDecl::<H> { ty: hir.unit_ty() }];
+ let temp_decls = vec![TempDecl::<'tcx> { ty: hir.unit_ty() }];
let unit_temp = Lvalue::Temp(0);
let mut builder = Builder {
builder.cfg.terminate(block, Terminator::Goto { target: END_BLOCK });
builder.cfg.terminate(END_BLOCK, Terminator::Return);
- Mir {
+ Mir {
basic_blocks: builder.cfg.basic_blocks,
extents: builder.extents,
var_decls: builder.var_decls,
}
}
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
fn args_and_body(&mut self,
mut block: BasicBlock,
- implicit_arguments: Vec<H::Ty>,
- explicit_arguments: Vec<(H::Ty, H::Pattern)>,
- argument_extent: H::CodeExtent,
- ast_block: H::Block)
- -> BlockAnd<Vec<ArgDecl<H>>>
+ implicit_arguments: Vec<Ty<'tcx>>,
+ explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
+ argument_extent: CodeExtent,
+ ast_block: &'tcx hir::Block)
+ -> BlockAnd<Vec<ArgDecl<'tcx>>>
{
self.in_scope(argument_extent, block, |this| {
let arg_decls = {
mod misc;
mod scope;
mod stmt;
-
Managing the scope stack. The scopes are tied to lexical scopes, so as
we descend the HAIR, we push a scope on the stack, translate ite
contents, and then pop it off. Every scope is named by a
-`H::CodeExtent`.
+`CodeExtent`.
### SEME Regions
from the scope. Each lexical scope thus corresponds to a single-entry,
multiple-exit (SEME) region in the control-flow graph.
-For now, we keep a mapping from each `H::CodeExtent` to its
+For now, we keep a mapping from each `CodeExtent` to its
corresponding SEME region for later reference (see caveat in next
paragraph). This is because region scopes are tied to
them. Eventually, when we shift to non-lexical lifetimes, three should
*/
use build::{BlockAnd, Builder, CFG};
-use hair::Hair;
use repr::*;
+use rustc::middle::region::CodeExtent;
+use rustc::middle::ty::Ty;
+use syntax::codemap::Span;
-pub struct Scope<H:Hair> {
- extent: H::CodeExtent,
+pub struct Scope<'tcx> {
+ extent: CodeExtent,
exits: Vec<ExecutionPoint>,
- drops: Vec<(DropKind, H::Span, Lvalue<H>)>,
+ drops: Vec<(DropKind, Span, Lvalue<'tcx>)>,
cached_block: Option<BasicBlock>,
}
#[derive(Clone, Debug)]
-pub struct LoopScope<H:Hair> {
- pub extent: H::CodeExtent, // extent of the loop
+pub struct LoopScope {
+ pub extent: CodeExtent, // extent of the loop
pub continue_block: BasicBlock, // where to go on a `loop`
- pub break_block: BasicBlock, // where to go on a `break
+ pub break_block: BasicBlock, // where to go on a `break
}
-impl<H:Hair> Builder<H> {
+impl<'a,'tcx> Builder<'a,'tcx> {
/// Start a loop scope, which tracks where `continue` and `break`
/// should branch to. See module comment for more details.
- pub fn in_loop_scope<F,R>(&mut self,
- loop_block: BasicBlock,
- break_block: BasicBlock,
- f: F)
- -> BlockAnd<R>
- where F: FnOnce(&mut Builder<H>) -> BlockAnd<R>
+ pub fn in_loop_scope<F, R>(&mut self,
+ loop_block: BasicBlock,
+ break_block: BasicBlock,
+ f: F)
+ -> BlockAnd<R>
+ where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>
{
let extent = self.extent_of_innermost_scope().unwrap();
- let loop_scope = LoopScope::<H> { extent: extent.clone(),
- continue_block: loop_block,
- break_block: break_block };
+ let loop_scope = LoopScope {
+ extent: extent.clone(),
+ continue_block: loop_block,
+ break_block: break_block,
+ };
self.loop_scopes.push(loop_scope);
let r = f(self);
assert!(self.loop_scopes.pop().unwrap().extent == extent);
/// Start a scope. The closure `f` should translate the contents
/// of the scope. See module comment for more details.
- pub fn in_scope<F,R>(&mut self,
- extent: H::CodeExtent,
- block: BasicBlock,
- f: F)
- -> BlockAnd<R>
- where F: FnOnce(&mut Builder<H>) -> BlockAnd<R>
+ pub fn in_scope<F, R>(&mut self, extent: CodeExtent, block: BasicBlock, f: F) -> BlockAnd<R>
+ where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>
{
debug!("in_scope(extent={:?}, block={:?})", extent, block);
/// exit points.
fn graph_extent(&self, entry: ExecutionPoint, exits: Vec<ExecutionPoint>) -> GraphExtent {
if exits.len() == 1 && entry.block == exits[0].block {
- GraphExtent { entry: entry, exit: GraphExtentExit::Statement(exits[0].statement) }
+ GraphExtent {
+ entry: entry,
+ exit: GraphExtentExit::Statement(exits[0].statement),
+ }
} else {
- GraphExtent { entry: entry, exit: GraphExtentExit::Points(exits) }
+ GraphExtent {
+ entry: entry,
+ exit: GraphExtentExit::Points(exits),
+ }
}
}
/// Finds the loop scope for a given label. This is used for
/// resolving `break` and `continue`.
pub fn find_loop_scope(&mut self,
- span: H::Span,
- label: Option<H::CodeExtent>)
- -> LoopScope<H> {
+ span: Span,
+ label: Option<CodeExtent>)
+ -> LoopScope {
let loop_scope =
match label {
None => {
match loop_scope {
Some(loop_scope) => loop_scope.clone(),
- None => self.hir.span_bug(span, "no enclosing loop scope found?")
+ None => self.hir.span_bug(span, "no enclosing loop scope found?"),
}
}
/// needed, as well as tracking this exit for the SEME region. See
/// module comment for details.
pub fn exit_scope(&mut self,
- span: H::Span,
- extent: H::CodeExtent,
+ span: Span,
+ extent: CodeExtent,
block: BasicBlock,
target: BasicBlock) {
let popped_scopes =
/// Indicates that `lvalue` should be dropped on exit from
/// `extent`.
pub fn schedule_drop(&mut self,
- span: H::Span,
- extent: H::CodeExtent,
+ span: Span,
+ extent: CodeExtent,
kind: DropKind,
- lvalue: &Lvalue<H>,
- lvalue_ty: H::Ty)
- {
+ lvalue: &Lvalue<'tcx>,
+ lvalue_ty: Ty<'tcx>) {
if self.hir.needs_drop(lvalue_ty, span) {
match self.scopes.iter_mut().rev().find(|s| s.extent == extent) {
Some(scope) => {
}
}
- pub fn extent_of_innermost_scope(&self) -> Option<H::CodeExtent> {
+ pub fn extent_of_innermost_scope(&self) -> Option<CodeExtent> {
self.scopes.last().map(|scope| scope.extent)
}
- pub fn extent_of_outermost_scope(&self) -> Option<H::CodeExtent> {
+ pub fn extent_of_outermost_scope(&self) -> Option<CodeExtent> {
self.scopes.first().map(|scope| scope.extent)
}
}
-fn diverge_cleanup_helper<H:Hair>(cfg: &mut CFG<H>,
- scopes: &mut [Scope<H>])
- -> BasicBlock {
+fn diverge_cleanup_helper<'tcx>(cfg: &mut CFG<'tcx>, scopes: &mut [Scope<'tcx>]) -> BasicBlock {
let len = scopes.len();
if len == 0 {
use hair::*;
use repr::*;
-impl<H:Hair> Builder<H> {
- pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec<StmtRef<H>>) -> BlockAnd<()> {
+impl<'a,'tcx> Builder<'a,'tcx> {
+ pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec<StmtRef<'tcx>>) -> BlockAnd<()> {
for stmt in stmts {
unpack!(block = self.stmt(block, stmt));
}
block.unit()
}
- pub fn stmt(&mut self, mut block: BasicBlock, stmt: StmtRef<H>) -> BlockAnd<()> {
+ pub fn stmt(&mut self, mut block: BasicBlock, stmt: StmtRef<'tcx>) -> BlockAnd<()> {
let this = self;
let Stmt { span, kind } = this.hir.mirror(stmt);
match kind {
StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => {
this.in_scope(remainder_scope, block, |this| {
unpack!(block = this.in_scope(init_scope, block, |this| {
- this.declare_uninitialized_variables(remainder_scope, pattern);
+ this.declare_bindings(remainder_scope, pattern);
block.unit()
}));
this.stmts(block, stmts)
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! An experimental pass that scources for `#[rustc_mir]` attributes,
-//! builds the resulting MIR, and dumps it out into a file for inspection.
-//!
-//! The attribute formats that are currently accepted are:
-//!
-//! - `#[rustc_mir(graphviz="file.gv")]`
-//! - `#[rustc_mir(pretty="file.mir")]`
-
-extern crate syntax;
-extern crate rustc;
-extern crate rustc_front;
-
-use build;
-use dot;
-use repr::Mir;
-use std::fs::File;
-use tcx::{PatNode, Cx};
-
-use self::rustc::middle::def_id::DefId;
-use self::rustc::middle::infer;
-use self::rustc::middle::region::CodeExtentData;
-use self::rustc::middle::ty::{self, Ty};
-use self::rustc::util::common::ErrorReported;
-use self::rustc_front::hir;
-use self::rustc_front::attr::{AttrMetaMethods};
-use self::rustc_front::visit;
-use self::syntax::ast;
-use self::syntax::codemap::Span;
-
-pub fn dump_crate(tcx: &ty::ctxt) {
- let mut dump = OuterDump { tcx: tcx };
- visit::walk_crate(&mut dump, tcx.map.krate());
-}
-
-///////////////////////////////////////////////////////////////////////////
-// OuterDump -- walks a crate, looking for fn items and methods to build MIR from
-
-struct OuterDump<'a,'tcx:'a> {
- tcx: &'a ty::ctxt<'tcx>,
-}
-
-impl<'a, 'tcx> OuterDump<'a, 'tcx> {
- fn visit_mir<OP>(&self, attributes: &'tcx [hir::Attribute], mut walk_op: OP)
- where OP: FnMut(&mut InnerDump<'a,'tcx>)
- {
- let mut built_mir = false;
-
- for attr in attributes {
- if attr.check_name("rustc_mir") {
- let mut closure_dump = InnerDump { tcx: self.tcx, attr: Some(attr) };
- walk_op(&mut closure_dump);
- built_mir = true;
- }
- }
-
- let always_build_mir = self.tcx.sess.opts.always_build_mir;
- if !built_mir && always_build_mir {
- let mut closure_dump = InnerDump { tcx: self.tcx, attr: None };
- walk_op(&mut closure_dump);
- }
- }
-}
-
-
-impl<'a, 'tcx> visit::Visitor<'tcx> for OuterDump<'a, 'tcx> {
- fn visit_item(&mut self, item: &'tcx hir::Item) {
- self.visit_mir(&item.attrs, |c| visit::walk_item(c, item));
- visit::walk_item(self, item);
- }
-
- fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
- match trait_item.node {
- hir::MethodTraitItem(_, Some(_)) => {
- self.visit_mir(&trait_item.attrs, |c| visit::walk_trait_item(c, trait_item));
- }
- _ => { }
- }
- visit::walk_trait_item(self, trait_item);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-// InnerDump -- dumps MIR for a single fn and its contained closures
-
-struct InnerDump<'a,'tcx:'a> {
- tcx: &'a ty::ctxt<'tcx>,
- attr: Option<&'a hir::Attribute>,
-}
-
-impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> {
- fn visit_item(&mut self, _: &'tcx hir::Item) {
- // ignore nested items; they need their own graphviz annotation
- }
-
- fn visit_fn(&mut self,
- fk: visit::FnKind<'tcx>,
- decl: &'tcx hir::FnDecl,
- body: &'tcx hir::Block,
- span: Span,
- id: ast::NodeId) {
- let (prefix, implicit_arg_tys) = match fk {
- visit::FnKind::Closure =>
- (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
- _ =>
- (format!(""), vec![]),
- };
-
- let param_env =
- ty::ParameterEnvironment::for_item(self.tcx, id);
-
- let infcx =
- infer::new_infer_ctxt(self.tcx,
- &self.tcx.tables,
- Some(param_env),
- true);
-
- match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
- Ok(mir) => {
- let meta_item_list =
- self.attr.iter()
- .flat_map(|a| a.meta_item_list())
- .flat_map(|l| l.iter());
- for item in meta_item_list {
- if item.check_name("graphviz") {
- match item.value_str() {
- Some(s) => {
- match
- File::create(format!("{}{}", prefix, s))
- .and_then(|ref mut output| dot::render(&mir, output))
- {
- Ok(()) => { }
- Err(e) => {
- self.tcx.sess.span_fatal(
- item.span,
- &format!("Error writing graphviz \
- results to `{}`: {}",
- s, e));
- }
- }
- }
- None => {
- self.tcx.sess.span_err(
- item.span,
- &format!("graphviz attribute requires a path"));
- }
- }
- }
- }
- }
- Err(ErrorReported) => { }
- }
-
- visit::walk_fn(self, fk, decl, body, span);
- }
-}
-
-fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
- implicit_arg_tys: Vec<Ty<'tcx>>,
- fn_id: ast::NodeId,
- span: Span,
- decl: &'tcx hir::FnDecl,
- body: &'tcx hir::Block)
- -> Result<Mir<Cx<'a,'tcx>>, ErrorReported> {
- let arguments =
- decl.inputs
- .iter()
- .map(|arg| {
- let ty = cx.tcx.node_id_to_type(arg.id);
- (ty, PatNode::irrefutable(&arg.pat))
- })
- .collect();
-
- let parameter_scope =
- cx.tcx.region_maps.lookup_code_extent(
- CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
- Ok(build::construct(cx,
- span,
- implicit_arg_tys,
- arguments,
- parameter_scope,
- body))
-}
-
-fn closure_self_ty<'a,'tcx>(tcx: &ty::ctxt<'tcx>,
- closure_expr_id: ast::NodeId,
- body_id: ast::NodeId)
- -> Ty<'tcx>
-{
- let closure_ty = tcx.node_id_to_type(closure_expr_id);
-
- // We're just hard-coding the idea that the signature will be
- // &self or &mut self and hence will have a bound region with
- // number 0, hokey.
- let region =
- ty::Region::ReFree(
- ty::FreeRegion {
- scope: tcx.region_maps.item_extent(body_id),
- bound_region: ty::BoundRegion::BrAnon(0)
- });
- let region =
- tcx.mk_region(region);
-
- match tcx.closure_kind(DefId::local(closure_expr_id)) {
- ty::ClosureKind::FnClosureKind =>
- tcx.mk_ref(region,
- ty::TypeAndMut { ty: closure_ty,
- mutbl: hir::MutImmutable }),
- ty::ClosureKind::FnMutClosureKind =>
- tcx.mk_ref(region,
- ty::TypeAndMut { ty: closure_ty,
- mutbl: hir::MutMutable }),
- ty::ClosureKind::FnOnceClosureKind =>
- closure_ty
- }
-}
// except according to those terms.
use dot;
-use hair::Hair;
use repr::*;
use std::borrow::IntoCow;
index: usize,
}
-impl<'a,H:Hair> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<H> {
+impl<'a,'tcx> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
fn graph_id(&'a self) -> dot::Id<'a> {
dot::Id::new("Mir").unwrap()
}
}
}
-impl<'a,H:Hair> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<H> {
+impl<'a,'tcx> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
fn nodes(&'a self) -> dot::Nodes<'a, BasicBlock> {
self.all_basic_blocks().into_cow()
}
self.all_basic_blocks()
.into_iter()
.flat_map(|source| {
- self.basic_block_data(source).terminator
- .successors()
- .iter()
- .enumerate()
- .map(move |(index, &target)| {
- EdgeIndex { source: source,
- target: target,
- index: index }
- })
+ self.basic_block_data(source)
+ .terminator
+ .successors()
+ .iter()
+ .enumerate()
+ .map(move |(index, &target)| {
+ EdgeIndex {
+ source: source,
+ target: target,
+ index: index,
+ }
+ })
})
.collect::<Vec<_>>()
.into_cow()
/// Returns an updated string if changes were made, else None.
fn to_subscript1(header: &str, text: &str, offset: &mut usize) -> Option<String> {
let a = match text[*offset..].find(header) {
- None => { *offset = text.len(); return None; }
+ None => {
+ *offset = text.len();
+ return None;
+ }
Some(a) => a + *offset,
};
result.push_str(&text[..b]);
while let Some(c) = chars.next() {
- if c == ')' { break; }
- if !c.is_digit(10) { return None; }
+ if c == ')' {
+ break;
+ }
+ if !c.is_digit(10) {
+ return None;
+ }
// 0x208 is _0 in unicode, 0x209 is _1, etc
const SUBSCRIPTS: &'static str = "₀₁₂₃₄₅₆₇₈₉";
//! structures.
use repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp};
-use std::fmt::Debug;
-use std::hash::Hash;
-
-pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*)
-
- // (*) the `Sized` and Debug` bounds are the only ones that really
- // make sense. The rest are just there so that we can
- // `#[derive(Clone)]` on things that are parameterized over
- // `H:HAIR`. It's kind of lame.
-
- type VarId: Copy+Debug+Eq+Hash; // e.g., NodeId for a variable
- type DefId: Copy+Debug+Eq+Hash; // e.g., DefId
- type AdtDef: Copy+Debug+Eq+Hash; // e.g., AdtDef<'tcx>
- type Name: Copy+Debug+Eq+Hash; // e.g., ast::Name
- type Ident: Copy+Debug+Eq+Hash; // e.g., ast::Ident
- type InternedString: Clone+Debug+Eq+Hash; // e.g., InternedString
- type Bytes: Clone+Debug+Eq+Hash; // e.g., Rc<Vec<u8>>
- type Span: Copy+Debug+Eq; // e.g., syntax::codemap::Span
- type Projection: Clone+Debug+Eq; // e.g., ty::ProjectionTy<'tcx>
- type Substs: Clone+Debug+Eq; // e.g., substs::Substs<'tcx>
- type ClosureSubsts: Clone+Debug+Eq; // e.g., ty::ClosureSubsts<'tcx>
- type Ty: Clone+Debug+Eq; // e.g., ty::Ty<'tcx>
- type Region: Copy+Debug; // e.g., ty::Region
- type CodeExtent: Copy+Debug+Hash+Eq; // e.g., region::CodeExtent
- type Pattern: Clone+Debug+Mirror<Self,Output=Pattern<Self>>; // e.g., &P<ast::Pat>
- type Expr: Clone+Debug+Mirror<Self,Output=Expr<Self>>; // e.g., &P<ast::Expr>
- type Stmt: Clone+Debug+Mirror<Self,Output=Stmt<Self>>; // e.g., &P<ast::Stmt>
- type Block: Clone+Debug+Mirror<Self,Output=Block<Self>>; // e.g., &P<ast::Block>
- type InlineAsm: Clone+Debug+Eq+Hash; // e.g., ast::InlineAsm
-
- /// Normalizes `ast` into the appropriate `mirror` type.
- fn mirror<M:Mirror<Self>>(&mut self, ast: M) -> M::Output {
- ast.make_mirror(self)
- }
-
- /// Returns the unit type `()`
- fn unit_ty(&mut self) -> Self::Ty;
-
- /// Returns the type `usize`.
- fn usize_ty(&mut self) -> Self::Ty;
-
- /// Returns the type `bool`.
- fn bool_ty(&mut self) -> Self::Ty;
-
- /// Returns a reference to `PartialEq::<T,T>::eq`
- fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef<Self>;
-
- /// Returns a reference to `PartialOrd::<T,T>::le`
- fn partial_le(&mut self, ty: Self::Ty) -> ItemRef<Self>;
-
- /// Returns the number of variants for the given enum
- fn num_variants(&mut self, adt: Self::AdtDef) -> usize;
-
- fn fields(&mut self, adt: Self::AdtDef, variant_index: usize) -> Vec<Field<Self>>;
-
- /// true if a value of type `ty` (may) need to be dropped; this
- /// may return false even for non-Copy types if there is no
- /// destructor to execute. If correct result is not known, may be
- /// approximated by returning `true`; this will result in more
- /// drops but not incorrect code.
- fn needs_drop(&mut self, ty: Self::Ty, span: Self::Span) -> bool;
-
- /// Report an internal inconsistency.
- fn span_bug(&mut self, span: Self::Span, message: &str) -> !;
-}
+use rustc::middle::def_id::DefId;
+use rustc::middle::region::CodeExtent;
+use rustc::middle::subst::Substs;
+use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
+use rustc_front::hir;
+use syntax::ast;
+use syntax::codemap::Span;
+use tcx::{Cx, PatNode};
#[derive(Clone, Debug)]
-pub struct ItemRef<H:Hair> {
- pub ty: H::Ty,
- pub def_id: H::DefId,
- pub substs: H::Substs,
+pub struct ItemRef<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub def_id: DefId,
+ pub substs: &'tcx Substs<'tcx>,
}
#[derive(Clone, Debug)]
-pub struct Block<H:Hair> {
- pub extent: H::CodeExtent,
- pub span: H::Span,
- pub stmts: Vec<StmtRef<H>>,
- pub expr: Option<ExprRef<H>>,
+pub struct Block<'tcx> {
+ pub extent: CodeExtent,
+ pub span: Span,
+ pub stmts: Vec<StmtRef<'tcx>>,
+ pub expr: Option<ExprRef<'tcx>>,
}
#[derive(Clone, Debug)]
-pub enum StmtRef<H:Hair> {
- Hair(H::Stmt),
- Mirror(Box<Stmt<H>>),
+pub enum StmtRef<'tcx> {
+ Hair(&'tcx hir::Stmt),
+ Mirror(Box<Stmt<'tcx>>),
}
#[derive(Clone, Debug)]
-pub struct Stmt<H:Hair> {
- pub span: H::Span,
- pub kind: StmtKind<H>,
+pub struct Stmt<'tcx> {
+ pub span: Span,
+ pub kind: StmtKind<'tcx>,
}
#[derive(Clone, Debug)]
-pub enum StmtKind<H:Hair> {
+pub enum StmtKind<'tcx> {
Expr {
/// scope for this statement; may be used as lifetime of temporaries
- scope: H::CodeExtent,
+ scope: CodeExtent,
/// expression being evaluated in this statement
- expr: ExprRef<H>
+ expr: ExprRef<'tcx>,
},
Let {
/// scope for variables bound in this let; covers this and
/// remaining statements in block
- remainder_scope: H::CodeExtent,
+ remainder_scope: CodeExtent,
/// scope for the initialization itself; might be used as
/// lifetime of temporaries
- init_scope: H::CodeExtent,
+ init_scope: CodeExtent,
/// let <PAT> = ...
- pattern: PatternRef<H>,
+ pattern: PatternRef<'tcx>,
/// let pat = <INIT> ...
- initializer: Option<ExprRef<H>>,
+ initializer: Option<ExprRef<'tcx>>,
/// let pat = init; <STMTS>
- stmts: Vec<StmtRef<H>>
+ stmts: Vec<StmtRef<'tcx>>,
},
}
-// The Hair trait implementor translates their expressions (`H::Expr`)
+// The Hair trait implementor translates their expressions (`&'tcx H::Expr`)
// into instances of this `Expr` enum. This translation can be done
// basically as lazilly or as eagerly as desired: every recursive
-// reference to an expression in this enum is an `ExprRef<H>`, which
+// reference to an expression in this enum is an `ExprRef<'tcx>`, which
// may in turn be another instance of this enum (boxed), or else an
-// untranslated `H::Expr`. Note that instances of `Expr` are very
+// untranslated `&'tcx H::Expr`. Note that instances of `Expr` are very
// shortlived. They are created by `Hair::to_expr`, analyzed and
// converted into MIR, and then discarded.
//
// example, method calls and overloaded operators are absent: they are
// expected to be converted into `Expr::Call` instances.
#[derive(Clone, Debug)]
-pub struct Expr<H:Hair> {
+pub struct Expr<'tcx> {
// type of this expression
- pub ty: H::Ty,
+ pub ty: Ty<'tcx>,
// lifetime of this expression if it should be spilled into a
// temporary; should be None only if in a constant context
- pub temp_lifetime: Option<H::CodeExtent>,
+ pub temp_lifetime: Option<CodeExtent>,
// span of the expression in the source
- pub span: H::Span,
+ pub span: Span,
// kind of expression
- pub kind: ExprKind<H>,
+ pub kind: ExprKind<'tcx>,
}
#[derive(Clone, Debug)]
-pub enum ExprKind<H:Hair> {
- Scope { extent: H::CodeExtent, value: ExprRef<H> },
- Paren { arg: ExprRef<H> }, // ugh. should be able to remove this!
- Box { place: Option<ExprRef<H>>, value: ExprRef<H> },
- Call { fun: ExprRef<H>, args: Vec<ExprRef<H>> },
- Deref { arg: ExprRef<H> }, // NOT overloaded!
- Binary { op: BinOp, lhs: ExprRef<H>, rhs: ExprRef<H> }, // NOT overloaded!
- LogicalOp { op: LogicalOp, lhs: ExprRef<H>, rhs: ExprRef<H> },
- Unary { op: UnOp, arg: ExprRef<H> }, // NOT overloaded!
- Cast { source: ExprRef<H> },
- ReifyFnPointer { source: ExprRef<H> },
- UnsafeFnPointer { source: ExprRef<H> },
- Unsize { source: ExprRef<H> },
- If { condition: ExprRef<H>, then: ExprRef<H>, otherwise: Option<ExprRef<H>> },
- Loop { condition: Option<ExprRef<H>>, body: ExprRef<H>, },
- Match { discriminant: ExprRef<H>, arms: Vec<Arm<H>> },
- Block { body: H::Block },
- Assign { lhs: ExprRef<H>, rhs: ExprRef<H> },
- AssignOp { op: BinOp, lhs: ExprRef<H>, rhs: ExprRef<H> },
- Field { lhs: ExprRef<H>, name: Field<H> },
- Index { lhs: ExprRef<H>, index: ExprRef<H> },
- VarRef { id: H::VarId },
+pub enum ExprKind<'tcx> {
+ Scope {
+ extent: CodeExtent,
+ value: ExprRef<'tcx>,
+ },
+ Box {
+ value: ExprRef<'tcx>,
+ },
+ Call {
+ fun: ExprRef<'tcx>,
+ args: Vec<ExprRef<'tcx>>,
+ },
+ Deref {
+ arg: ExprRef<'tcx>,
+ }, // NOT overloaded!
+ Binary {
+ op: BinOp,
+ lhs: ExprRef<'tcx>,
+ rhs: ExprRef<'tcx>,
+ }, // NOT overloaded!
+ LogicalOp {
+ op: LogicalOp,
+ lhs: ExprRef<'tcx>,
+ rhs: ExprRef<'tcx>,
+ },
+ Unary {
+ op: UnOp,
+ arg: ExprRef<'tcx>,
+ }, // NOT overloaded!
+ Cast {
+ source: ExprRef<'tcx>,
+ },
+ ReifyFnPointer {
+ source: ExprRef<'tcx>,
+ },
+ UnsafeFnPointer {
+ source: ExprRef<'tcx>,
+ },
+ Unsize {
+ source: ExprRef<'tcx>,
+ },
+ If {
+ condition: ExprRef<'tcx>,
+ then: ExprRef<'tcx>,
+ otherwise: Option<ExprRef<'tcx>>,
+ },
+ Loop {
+ condition: Option<ExprRef<'tcx>>,
+ body: ExprRef<'tcx>,
+ },
+ Match {
+ discriminant: ExprRef<'tcx>,
+ arms: Vec<Arm<'tcx>>,
+ },
+ Block {
+ body: &'tcx hir::Block,
+ },
+ Assign {
+ lhs: ExprRef<'tcx>,
+ rhs: ExprRef<'tcx>,
+ },
+ AssignOp {
+ op: BinOp,
+ lhs: ExprRef<'tcx>,
+ rhs: ExprRef<'tcx>,
+ },
+ Field {
+ lhs: ExprRef<'tcx>,
+ name: Field,
+ },
+ Index {
+ lhs: ExprRef<'tcx>,
+ index: ExprRef<'tcx>,
+ },
+ VarRef {
+ id: ast::NodeId,
+ },
SelfRef, // first argument, used for self in a closure
- StaticRef { id: H::DefId },
- Borrow { region: H::Region, borrow_kind: BorrowKind, arg: ExprRef<H> },
- Break { label: Option<H::CodeExtent> },
- Continue { label: Option<H::CodeExtent> },
- Return { value: Option<ExprRef<H>> },
- Repeat { value: ExprRef<H>, count: ExprRef<H> },
- Vec { fields: Vec<ExprRef<H>> },
- Tuple { fields: Vec<ExprRef<H>> },
- Adt { adt_def: H::AdtDef,
- variant_index: usize,
- substs: H::Substs,
- fields: Vec<FieldExprRef<H>>,
- base: Option<ExprRef<H>> },
- Closure { closure_id: H::DefId, substs: H::ClosureSubsts,
- upvars: Vec<ExprRef<H>> },
- Literal { literal: Literal<H> },
- InlineAsm { asm: H::InlineAsm },
+ StaticRef {
+ id: DefId,
+ },
+ Borrow {
+ region: Region,
+ borrow_kind: BorrowKind,
+ arg: ExprRef<'tcx>,
+ },
+ Break {
+ label: Option<CodeExtent>,
+ },
+ Continue {
+ label: Option<CodeExtent>,
+ },
+ Return {
+ value: Option<ExprRef<'tcx>>,
+ },
+ Repeat {
+ value: ExprRef<'tcx>,
+ count: ExprRef<'tcx>,
+ },
+ Vec {
+ fields: Vec<ExprRef<'tcx>>,
+ },
+ Tuple {
+ fields: Vec<ExprRef<'tcx>>,
+ },
+ Adt {
+ adt_def: AdtDef<'tcx>,
+ variant_index: usize,
+ substs: &'tcx Substs<'tcx>,
+ fields: Vec<FieldExprRef<'tcx>>,
+ base: Option<ExprRef<'tcx>>,
+ },
+ Closure {
+ closure_id: DefId,
+ substs: &'tcx ClosureSubsts<'tcx>,
+ upvars: Vec<ExprRef<'tcx>>,
+ },
+ Literal {
+ literal: Literal<'tcx>,
+ },
+ InlineAsm {
+ asm: &'tcx hir::InlineAsm,
+ },
}
#[derive(Clone, Debug)]
-pub enum ExprRef<H:Hair> {
- Hair(H::Expr),
- Mirror(Box<Expr<H>>),
+pub enum ExprRef<'tcx> {
+ Hair(&'tcx hir::Expr),
+ Mirror(Box<Expr<'tcx>>),
}
#[derive(Clone, Debug)]
-pub struct FieldExprRef<H:Hair> {
- pub name: Field<H>,
- pub expr: ExprRef<H>,
+pub struct FieldExprRef<'tcx> {
+ pub name: Field,
+ pub expr: ExprRef<'tcx>,
}
#[derive(Clone, Debug)]
-pub struct Arm<H:Hair> {
- pub patterns: Vec<PatternRef<H>>,
- pub guard: Option<ExprRef<H>>,
- pub body: ExprRef<H>,
+pub struct Arm<'tcx> {
+ pub patterns: Vec<PatternRef<'tcx>>,
+ pub guard: Option<ExprRef<'tcx>>,
+ pub body: ExprRef<'tcx>,
}
#[derive(Clone, Debug)]
-pub struct Pattern<H:Hair> {
- pub ty: H::Ty,
- pub span: H::Span,
- pub kind: PatternKind<H>,
+pub struct Pattern<'tcx> {
+ pub ty: Ty<'tcx>,
+ pub span: Span,
+ pub kind: PatternKind<'tcx>,
}
#[derive(Copy, Clone, Debug)]
pub enum LogicalOp {
And,
- Or
+ Or,
}
#[derive(Clone, Debug)]
-pub enum PatternKind<H:Hair> {
+pub enum PatternKind<'tcx> {
Wild,
// x, ref x, x @ P, etc
- Binding { mutability: Mutability,
- name: H::Ident,
- mode: BindingMode<H>,
- var: H::VarId,
- ty: H::Ty,
- subpattern: Option<PatternRef<H>> },
+ Binding {
+ mutability: Mutability,
+ name: ast::Name,
+ mode: BindingMode,
+ var: ast::NodeId,
+ ty: Ty<'tcx>,
+ subpattern: Option<PatternRef<'tcx>>,
+ },
// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
- Variant { adt_def: H::AdtDef, variant_index: usize, subpatterns: Vec<FieldPatternRef<H>> },
+ Variant {
+ adt_def: AdtDef<'tcx>,
+ variant_index: usize,
+ subpatterns: Vec<FieldPatternRef<'tcx>>,
+ },
// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
- Leaf { subpatterns: Vec<FieldPatternRef<H>> },
+ Leaf {
+ subpatterns: Vec<FieldPatternRef<'tcx>>,
+ },
- Deref { subpattern: PatternRef<H> }, // box P, &P, &mut P, etc
+ Deref {
+ subpattern: PatternRef<'tcx>,
+ }, // box P, &P, &mut P, etc
- Constant { expr: ExprRef<H> },
+ Constant {
+ value: Literal<'tcx>,
+ },
- Range { lo: ExprRef<H>, hi: ExprRef<H> },
+ Range {
+ lo: Literal<'tcx>,
+ hi: Literal<'tcx>,
+ },
// matches against a slice, checking the length and extracting elements
- Slice { prefix: Vec<PatternRef<H>>,
- slice: Option<PatternRef<H>>,
- suffix: Vec<PatternRef<H>> },
+ Slice {
+ prefix: Vec<PatternRef<'tcx>>,
+ slice: Option<PatternRef<'tcx>>,
+ suffix: Vec<PatternRef<'tcx>>,
+ },
// fixed match against an array, irrefutable
- Array { prefix: Vec<PatternRef<H>>,
- slice: Option<PatternRef<H>>,
- suffix: Vec<PatternRef<H>> },
+ Array {
+ prefix: Vec<PatternRef<'tcx>>,
+ slice: Option<PatternRef<'tcx>>,
+ suffix: Vec<PatternRef<'tcx>>,
+ },
}
#[derive(Copy, Clone, Debug)]
-pub enum BindingMode<H:Hair> {
+pub enum BindingMode {
ByValue,
- ByRef(H::Region, BorrowKind),
+ ByRef(Region, BorrowKind),
}
#[derive(Clone, Debug)]
-pub enum PatternRef<H:Hair> {
- Hair(H::Pattern),
- Mirror(Box<Pattern<H>>),
+pub enum PatternRef<'tcx> {
+ Hair(PatNode<'tcx>),
+ Mirror(Box<Pattern<'tcx>>),
}
#[derive(Clone, Debug)]
-pub struct FieldPatternRef<H:Hair> {
- pub field: Field<H>,
- pub pattern: PatternRef<H>,
+pub struct FieldPatternRef<'tcx> {
+ pub field: Field,
+ pub pattern: PatternRef<'tcx>,
}
///////////////////////////////////////////////////////////////////////////
// The Mirror trait
-/// "Mirroring" is the process of converting from a Hair type into one
-/// of the types in this file. For example, the mirror of a `H::Expr`
-/// is an `Expr<H>`. Mirroring is the point at which the actual IR is
-/// converting into the more idealized representation described in
-/// this file. Mirroring is gradual: when you mirror an outer
-/// expression like `e1 + e2`, the references to the inner expressions
-/// `e1` and `e2` are `ExprRef<H>` instances, and they may or may not
-/// be eagerly mirrored. This allows a single AST node from the
-/// compiler to expand into one or more Hair nodes, which lets the Hair
-/// nodes be simpler.
-pub trait Mirror<H:Hair> {
+/// "Mirroring" is the process of converting from a HIR type into one
+/// of the HAIR types defined in this file. This is basically a "on
+/// the fly" desugaring step that hides a lot of the messiness in the
+/// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
+/// `Expr<'tcx>`.
+///
+/// Mirroring is gradual: when you mirror an outer expression like `e1
+/// + e2`, the references to the inner expressions `e1` and `e2` are
+/// `ExprRef<'tcx>` instances, and they may or may not be eagerly
+/// mirrored. This allows a single AST node from the compiler to
+/// expand into one or more Hair nodes, which lets the Hair nodes be
+/// simpler.
+pub trait Mirror<'tcx> {
type Output;
- fn make_mirror(self, hir: &mut H) -> Self::Output;
+ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Self::Output;
}
-impl<H:Hair> Mirror<H> for Expr<H> {
- type Output = Expr<H>;
+impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
+ type Output = Expr<'tcx>;
- fn make_mirror(self, _: &mut H) -> Expr<H> {
+ fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
self
}
}
-impl<H:Hair> Mirror<H> for ExprRef<H> {
- type Output = Expr<H>;
+impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
+ type Output = Expr<'tcx>;
- fn make_mirror(self, hir: &mut H) -> Expr<H> {
+ fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
match self {
ExprRef::Hair(h) => h.make_mirror(hir),
ExprRef::Mirror(m) => *m,
}
}
-impl<H:Hair> Mirror<H> for Stmt<H> {
- type Output = Stmt<H>;
+impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
+ type Output = Stmt<'tcx>;
- fn make_mirror(self, _: &mut H) -> Stmt<H> {
+ fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> {
self
}
}
-impl<H:Hair> Mirror<H> for StmtRef<H> {
- type Output = Stmt<H>;
+impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
+ type Output = Stmt<'tcx>;
- fn make_mirror(self, hir: &mut H) -> Stmt<H> {
+ fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> {
match self {
StmtRef::Hair(h) => h.make_mirror(hir),
StmtRef::Mirror(m) => *m,
}
}
-impl<H:Hair> Mirror<H> for Pattern<H> {
- type Output = Pattern<H>;
+impl<'tcx> Mirror<'tcx> for Pattern<'tcx> {
+ type Output = Pattern<'tcx>;
- fn make_mirror(self, _: &mut H) -> Pattern<H> {
+ fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> {
self
}
}
-impl<H:Hair> Mirror<H> for PatternRef<H> {
- type Output = Pattern<H>;
+impl<'tcx> Mirror<'tcx> for PatternRef<'tcx> {
+ type Output = Pattern<'tcx>;
- fn make_mirror(self, hir: &mut H) -> Pattern<H> {
+ fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> {
match self {
PatternRef::Hair(h) => h.make_mirror(hir),
PatternRef::Mirror(m) => *m,
}
}
-impl<H:Hair> Mirror<H> for Block<H> {
- type Output = Block<H>;
+impl<'tcx> Mirror<'tcx> for Block<'tcx> {
+ type Output = Block<'tcx>;
- fn make_mirror(self, _: &mut H) -> Block<H> {
+ fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Block<'tcx> {
self
}
}
-
#![crate_type = "rlib"]
#![crate_type = "dylib"]
-#![feature(ref_slice)]
#![feature(rustc_private)]
#![feature(into_cow)]
#[macro_use] extern crate log;
extern crate graphviz as dot;
+extern crate rustc;
extern crate rustc_data_structures;
+extern crate rustc_front;
+extern crate rustc_back;
+extern crate syntax;
pub mod build;
-pub mod dump;
+pub mod mir_map;
pub mod hair;
pub mod repr;
mod graphviz;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! An experimental pass that scources for `#[rustc_mir]` attributes,
+//! builds the resulting MIR, and dumps it out into a file for inspection.
+//!
+//! The attribute formats that are currently accepted are:
+//!
+//! - `#[rustc_mir(graphviz="file.gv")]`
+//! - `#[rustc_mir(pretty="file.mir")]`
+
+extern crate syntax;
+extern crate rustc;
+extern crate rustc_front;
+
+use build;
+use dot;
+use repr::Mir;
+use std::fs::File;
+use tcx::{PatNode, Cx};
+
+use self::rustc::middle::infer;
+use self::rustc::middle::region::CodeExtentData;
+use self::rustc::middle::ty::{self, Ty};
+use self::rustc::util::common::ErrorReported;
+use self::rustc::util::nodemap::NodeMap;
+use self::rustc_front::hir;
+use self::rustc_front::visit;
+use self::syntax::ast;
+use self::syntax::attr::AttrMetaMethods;
+use self::syntax::codemap::Span;
+
+pub type MirMap<'tcx> = NodeMap<Mir<'tcx>>;
+
+pub fn build_mir_for_crate<'tcx>(tcx: &ty::ctxt<'tcx>) -> MirMap<'tcx> {
+ let mut map = NodeMap();
+ {
+ let mut dump = OuterDump {
+ tcx: tcx,
+ map: &mut map,
+ };
+ visit::walk_crate(&mut dump, tcx.map.krate());
+ }
+ map
+}
+
+///////////////////////////////////////////////////////////////////////////
+// OuterDump -- walks a crate, looking for fn items and methods to build MIR from
+
+struct OuterDump<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ map: &'a mut MirMap<'tcx>,
+}
+
+impl<'a, 'tcx> OuterDump<'a, 'tcx> {
+ fn visit_mir<OP>(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP)
+ where OP: for<'m> FnMut(&mut InnerDump<'a, 'm, 'tcx>)
+ {
+ let mut closure_dump = InnerDump {
+ tcx: self.tcx,
+ attr: None,
+ map: &mut *self.map,
+ };
+ for attr in attributes {
+ if attr.check_name("rustc_mir") {
+ closure_dump.attr = Some(attr);
+ }
+ }
+ walk_op(&mut closure_dump);
+ }
+}
+
+
+impl<'a, 'tcx> visit::Visitor<'tcx> for OuterDump<'a, 'tcx> {
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
+ self.visit_mir(&item.attrs, |c| visit::walk_item(c, item));
+ visit::walk_item(self, item);
+ }
+
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ match trait_item.node {
+ hir::MethodTraitItem(_, Some(_)) => {
+ self.visit_mir(&trait_item.attrs, |c| visit::walk_trait_item(c, trait_item));
+ }
+ hir::MethodTraitItem(_, None) |
+ hir::ConstTraitItem(..) |
+ hir::TypeTraitItem(..) => {}
+ }
+ visit::walk_trait_item(self, trait_item);
+ }
+
+ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
+ match impl_item.node {
+ hir::MethodImplItem(..) => {
+ self.visit_mir(&impl_item.attrs, |c| visit::walk_impl_item(c, impl_item));
+ }
+ hir::ConstImplItem(..) | hir::TypeImplItem(..) => {}
+ }
+ visit::walk_impl_item(self, impl_item);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////
+// InnerDump -- dumps MIR for a single fn and its contained closures
+
+struct InnerDump<'a, 'm, 'tcx: 'a + 'm> {
+ tcx: &'a ty::ctxt<'tcx>,
+ map: &'m mut MirMap<'tcx>,
+ attr: Option<&'a ast::Attribute>,
+}
+
+impl<'a, 'm, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
+ fn visit_item(&mut self, _: &'tcx hir::Item) {
+ // ignore nested items; they need their own graphviz annotation
+ }
+
+ fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {
+ // ignore nested items; they need their own graphviz annotation
+ }
+
+ fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {
+ // ignore nested items; they need their own graphviz annotation
+ }
+
+ fn visit_fn(&mut self,
+ fk: visit::FnKind<'tcx>,
+ decl: &'tcx hir::FnDecl,
+ body: &'tcx hir::Block,
+ span: Span,
+ id: ast::NodeId) {
+ let (prefix, implicit_arg_tys) = match fk {
+ visit::FnKind::Closure =>
+ (format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
+ _ =>
+ (format!(""), vec![]),
+ };
+
+ let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
+
+ let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env), true);
+
+ match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
+ Ok(mir) => {
+ let meta_item_list = self.attr
+ .iter()
+ .flat_map(|a| a.meta_item_list())
+ .flat_map(|l| l.iter());
+ for item in meta_item_list {
+ if item.check_name("graphviz") {
+ match item.value_str() {
+ Some(s) => {
+ match
+ File::create(format!("{}{}", prefix, s))
+ .and_then(|ref mut output| dot::render(&mir, output))
+ {
+ Ok(()) => { }
+ Err(e) => {
+ self.tcx.sess.span_fatal(
+ item.span,
+ &format!("Error writing graphviz \
+ results to `{}`: {}",
+ s, e));
+ }
+ }
+ }
+ None => {
+ self.tcx.sess.span_err(
+ item.span,
+ &format!("graphviz attribute requires a path"));
+ }
+ }
+ }
+ }
+
+ let previous = self.map.insert(id, mir);
+ assert!(previous.is_none());
+ }
+ Err(ErrorReported) => {}
+ }
+
+ visit::walk_fn(self, fk, decl, body, span);
+ }
+}
+
+fn build_mir<'a, 'tcx: 'a>(cx: Cx<'a, 'tcx>,
+ implicit_arg_tys: Vec<Ty<'tcx>>,
+ fn_id: ast::NodeId,
+ span: Span,
+ decl: &'tcx hir::FnDecl,
+ body: &'tcx hir::Block)
+ -> Result<Mir<'tcx>, ErrorReported> {
+ let arguments = decl.inputs
+ .iter()
+ .map(|arg| {
+ let ty = cx.tcx().node_id_to_type(arg.id);
+ (ty, PatNode::irrefutable(&arg.pat))
+ })
+ .collect();
+
+ let parameter_scope = cx.tcx().region_maps.lookup_code_extent(CodeExtentData::ParameterScope {
+ fn_id: fn_id,
+ body_id: body.id,
+ });
+ Ok(build::construct(cx, span, implicit_arg_tys, arguments, parameter_scope, body))
+}
+
+fn closure_self_ty<'a, 'tcx>(tcx: &ty::ctxt<'tcx>,
+ closure_expr_id: ast::NodeId,
+ body_id: ast::NodeId)
+ -> Ty<'tcx> {
+ let closure_ty = tcx.node_id_to_type(closure_expr_id);
+
+ // We're just hard-coding the idea that the signature will be
+ // &self or &mut self and hence will have a bound region with
+ // number 0, hokey.
+ let region = ty::Region::ReFree(ty::FreeRegion {
+ scope: tcx.region_maps.item_extent(body_id),
+ bound_region: ty::BoundRegion::BrAnon(0),
+ });
+ let region = tcx.mk_region(region);
+
+ match tcx.closure_kind(tcx.map.local_def_id(closure_expr_id)) {
+ ty::ClosureKind::FnClosureKind =>
+ tcx.mk_ref(region,
+ ty::TypeAndMut { ty: closure_ty,
+ mutbl: hir::MutImmutable }),
+ ty::ClosureKind::FnMutClosureKind =>
+ tcx.mk_ref(region,
+ ty::TypeAndMut { ty: closure_ty,
+ mutbl: hir::MutMutable }),
+ ty::ClosureKind::FnOnceClosureKind =>
+ closure_ty
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use hair::Hair;
+use rustc::middle::const_eval::ConstVal;
+use rustc::middle::def_id::DefId;
+use rustc::middle::region::CodeExtent;
+use rustc::middle::subst::Substs;
+use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
+use rustc_back::slice;
use rustc_data_structures::fnv::FnvHashMap;
+use rustc_front::hir::InlineAsm;
+use syntax::ast::Name;
+use syntax::codemap::Span;
use std::fmt::{Debug, Formatter, Error};
-use std::slice;
use std::u32;
/// Lowered representation of a single function.
-pub struct Mir<H:Hair> {
- pub basic_blocks: Vec<BasicBlockData<H>>,
+pub struct Mir<'tcx> {
+ pub basic_blocks: Vec<BasicBlockData<'tcx>>,
// for every node id
- pub extents: FnvHashMap<H::CodeExtent, Vec<GraphExtent>>,
+ pub extents: FnvHashMap<CodeExtent, Vec<GraphExtent>>,
- pub var_decls: Vec<VarDecl<H>>,
- pub arg_decls: Vec<ArgDecl<H>>,
- pub temp_decls: Vec<TempDecl<H>>,
+ pub var_decls: Vec<VarDecl<'tcx>>,
+ pub arg_decls: Vec<ArgDecl<'tcx>>,
+ pub temp_decls: Vec<TempDecl<'tcx>>,
}
/// where execution begins
/// where execution ends, on panic
pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2);
-impl<H:Hair> Mir<H> {
+impl<'tcx> Mir<'tcx> {
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
(0..self.basic_blocks.len())
.map(|i| BasicBlock::new(i))
.collect()
}
- pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<H> {
+ pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> {
&self.basic_blocks[bb.index()]
}
- pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<H> {
+ pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> {
&mut self.basic_blocks[bb.index()]
}
}
Unique,
/// Data is mutable and not aliasable.
- Mut
+ Mut,
}
///////////////////////////////////////////////////////////////////////////
// A "variable" is a binding declared by the user as part of the fn
// decl, a let, etc.
-pub struct VarDecl<H:Hair> {
+pub struct VarDecl<'tcx> {
pub mutability: Mutability,
- pub name: H::Ident,
- pub ty: H::Ty,
+ pub name: Name,
+ pub ty: Ty<'tcx>,
}
// A "temp" is a temporary that we place on the stack. They are
// anonymous, always mutable, and have only a type.
-pub struct TempDecl<H:Hair> {
- pub ty: H::Ty,
+pub struct TempDecl<'tcx> {
+ pub ty: Ty<'tcx>,
}
// A "arg" is one of the function's formal arguments. These are
//
// there is only one argument, of type `(i32, u32)`, but two bindings
// (`x` and `y`).
-pub struct ArgDecl<H:Hair> {
- pub ty: H::Ty,
+pub struct ArgDecl<'tcx> {
+ pub ty: Ty<'tcx>,
}
///////////////////////////////////////////////////////////////////////////
// BasicBlock and Terminator
#[derive(Debug)]
-pub struct BasicBlockData<H:Hair> {
- pub statements: Vec<Statement<H>>,
- pub terminator: Terminator<H>,
+pub struct BasicBlockData<'tcx> {
+ pub statements: Vec<Statement<'tcx>>,
+ pub terminator: Terminator<'tcx>,
}
-pub enum Terminator<H:Hair> {
+pub enum Terminator<'tcx> {
/// block should have one successor in the graph; we jump there
- Goto { target: BasicBlock },
+ Goto {
+ target: BasicBlock,
+ },
/// block should initiate unwinding; should be one successor
/// that does cleanup and branches to DIVERGE_BLOCK
- Panic { target: BasicBlock },
+ Panic {
+ target: BasicBlock,
+ },
/// jump to branch 0 if this lvalue evaluates to true
- If { cond: Operand<H>, targets: [BasicBlock; 2] },
+ If {
+ cond: Operand<'tcx>,
+ targets: [BasicBlock; 2],
+ },
/// lvalue evaluates to some enum; jump depending on the branch
- Switch { discr: Lvalue<H>, targets: Vec<BasicBlock> },
+ Switch {
+ discr: Lvalue<'tcx>,
+ targets: Vec<BasicBlock>,
+ },
/// Indicates that the last statement in the block panics, aborts,
/// etc. No successors. This terminator appears on exactly one
/// block ends with a call; it should have two successors. The
/// first successor indicates normal return. The second indicates
/// unwinding.
- Call { data: CallData<H>, targets: [BasicBlock; 2] },
+ Call {
+ data: CallData<'tcx>,
+ targets: [BasicBlock; 2],
+ },
}
-impl<H:Hair> Terminator<H> {
+impl<'tcx> Terminator<'tcx> {
pub fn successors(&self) -> &[BasicBlock] {
use self::Terminator::*;
match *self {
}
#[derive(Debug)]
-pub struct CallData<H:Hair> {
+pub struct CallData<'tcx> {
/// where the return value is written to
- pub destination: Lvalue<H>,
+ pub destination: Lvalue<'tcx>,
/// the fn being called
- pub func: Lvalue<H>,
+ pub func: Lvalue<'tcx>,
/// the arguments
- pub args: Vec<Lvalue<H>>,
+ pub args: Vec<Lvalue<'tcx>>,
}
-impl<H:Hair> BasicBlockData<H> {
- pub fn new(terminator: Terminator<H>) -> BasicBlockData<H> {
+impl<'tcx> BasicBlockData<'tcx> {
+ pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
BasicBlockData {
statements: vec![],
terminator: terminator,
}
}
-impl<H:Hair> Debug for Terminator<H> {
+impl<'tcx> Debug for Terminator<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
use self::Terminator::*;
match *self {
Call { data: ref c, targets } => {
try!(write!(fmt, "{:?} = {:?}(", c.destination, c.func));
for (index, arg) in c.args.iter().enumerate() {
- if index > 0 { try!(write!(fmt, ", ")); }
+ if index > 0 {
+ try!(write!(fmt, ", "));
+ }
try!(write!(fmt, "{:?}", arg));
}
write!(fmt, ") -> {:?}", targets)
///////////////////////////////////////////////////////////////////////////
// Statements
-pub struct Statement<H:Hair> {
- pub span: H::Span,
- pub kind: StatementKind<H>,
+pub struct Statement<'tcx> {
+ pub span: Span,
+ pub kind: StatementKind<'tcx>,
}
#[derive(Debug)]
-pub enum StatementKind<H:Hair> {
- Assign(Lvalue<H>, Rvalue<H>),
- Drop(DropKind, Lvalue<H>),
+pub enum StatementKind<'tcx> {
+ Assign(Lvalue<'tcx>, Rvalue<'tcx>),
+ Drop(DropKind, Lvalue<'tcx>),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DropKind {
Shallow,
- Deep
+ Deep,
}
-impl<H:Hair> Debug for Statement<H> {
+impl<'tcx> Debug for Statement<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
use self::StatementKind::*;
match self.kind {
/// A path to a value; something that can be evaluated without
/// changing or disturbing program state.
#[derive(Clone, PartialEq)]
-pub enum Lvalue<H:Hair> {
+pub enum Lvalue<'tcx> {
/// local variable declared by the user
Var(u32),
Arg(u32),
/// static or static mut variable
- Static(H::DefId),
+ Static(DefId),
/// the return pointer of the fn
ReturnPointer,
/// projection out of an lvalue (access a field, deref a pointer, etc)
- Projection(Box<LvalueProjection<H>>)
+ Projection(Box<LvalueProjection<'tcx>>),
}
/// The `Projection` data structure defines things of the form `B.x`
/// shared between `Constant` and `Lvalue`. See the aliases
/// `LvalueProjection` etc below.
#[derive(Clone, Debug, PartialEq)]
-pub struct Projection<H:Hair,B,V> {
+pub struct Projection<'tcx, B, V> {
pub base: B,
- pub elem: ProjectionElem<H,V>,
+ pub elem: ProjectionElem<'tcx, V>,
}
#[derive(Clone, Debug, PartialEq)]
-pub enum ProjectionElem<H:Hair,V> {
+pub enum ProjectionElem<'tcx, V> {
Deref,
- Field(Field<H>),
+ Field(Field),
Index(V),
// These indices are generated by slice patterns. Easiest to explain
// "Downcast" to a variant of an ADT. Currently, we only introduce
// this for ADTs with more than one variant. It may be better to
// just introduce it always, or always for enums.
- Downcast(H::AdtDef, usize),
+ Downcast(AdtDef<'tcx>, usize),
}
/// Alias for projections as they appear in lvalues, where the base is an lvalue
/// and the index is an operand.
-pub type LvalueProjection<H> =
- Projection<H,Lvalue<H>,Operand<H>>;
+pub type LvalueProjection<'tcx> =
+ Projection<'tcx,Lvalue<'tcx>,Operand<'tcx>>;
/// Alias for projections as they appear in lvalues, where the base is an lvalue
/// and the index is an operand.
-pub type LvalueElem<H> =
- ProjectionElem<H,Operand<H>>;
+pub type LvalueElem<'tcx> =
+ ProjectionElem<'tcx,Operand<'tcx>>;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum Field<H:Hair> {
- Named(H::Name),
+pub enum Field {
+ Named(Name),
Indexed(usize),
}
-impl<H:Hair> Lvalue<H> {
- pub fn field(self, f: Field<H>) -> Lvalue<H> {
+impl<'tcx> Lvalue<'tcx> {
+ pub fn field(self, f: Field) -> Lvalue<'tcx> {
self.elem(ProjectionElem::Field(f))
}
- pub fn deref(self) -> Lvalue<H> {
+ pub fn deref(self) -> Lvalue<'tcx> {
self.elem(ProjectionElem::Deref)
}
- pub fn index(self, index: Operand<H>) -> Lvalue<H> {
+ pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> {
self.elem(ProjectionElem::Index(index))
}
- pub fn elem(self, elem: LvalueElem<H>) -> Lvalue<H> {
- Lvalue::Projection(Box::new(LvalueProjection { base: self, elem: elem }))
+ pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> {
+ Lvalue::Projection(Box::new(LvalueProjection {
+ base: self,
+ elem: elem,
+ }))
}
}
-impl<H:Hair> Debug for Lvalue<H> {
+impl<'tcx> Debug for Lvalue<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
use self::Lvalue::*;
// being nested in one another.
#[derive(Clone, PartialEq)]
-pub enum Operand<H:Hair> {
- Consume(Lvalue<H>),
- Constant(Constant<H>),
+pub enum Operand<'tcx> {
+ Consume(Lvalue<'tcx>),
+ Constant(Constant<'tcx>),
}
-impl<H:Hair> Debug for Operand<H> {
+impl<'tcx> Debug for Operand<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
use self::Operand::*;
match *self {
// Rvalues
#[derive(Clone)]
-pub enum Rvalue<H:Hair> {
+pub enum Rvalue<'tcx> {
// x (either a move or copy, depending on type of x)
- Use(Operand<H>),
+ Use(Operand<'tcx>),
// [x; 32]
- Repeat(Operand<H>, Operand<H>),
+ Repeat(Operand<'tcx>, Operand<'tcx>),
// &x or &mut x
- Ref(H::Region, BorrowKind, Lvalue<H>),
+ Ref(Region, BorrowKind, Lvalue<'tcx>),
// length of a [X] or [X;n] value
- Len(Lvalue<H>),
+ Len(Lvalue<'tcx>),
- Cast(CastKind, Operand<H>, H::Ty),
+ Cast(CastKind, Operand<'tcx>, Ty<'tcx>),
- BinaryOp(BinOp, Operand<H>, Operand<H>),
+ BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>),
- UnaryOp(UnOp, Operand<H>),
+ UnaryOp(UnOp, Operand<'tcx>),
// Creates an *uninitialized* Box
- Box(H::Ty),
+ Box(Ty<'tcx>),
// Create an aggregate value, like a tuple or struct. This is
// only needed because we want to distinguish `dest = Foo { x:
// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case
// that `Foo` has a destructor. These rvalues can be optimized
// away after type-checking and before lowering.
- Aggregate(AggregateKind<H>, Vec<Operand<H>>),
+ Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>),
// Generates a slice of the form `&input[from_start..L-from_end]`
// where `L` is the length of the slice. This is only created by
// .., z]` might create a slice with `from_start=2` and
// `from_end=1`.
Slice {
- input: Lvalue<H>,
+ input: Lvalue<'tcx>,
from_start: usize,
from_end: usize,
},
- InlineAsm(H::InlineAsm),
+ InlineAsm(&'tcx InlineAsm),
}
#[derive(Clone, Debug, PartialEq, Eq)]
}
#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum AggregateKind<H:Hair> {
+pub enum AggregateKind<'tcx> {
Vec,
Tuple,
- Adt(H::AdtDef, usize, H::Substs),
- Closure(H::DefId, H::ClosureSubsts),
+ Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>),
+ Closure(DefId, &'tcx ClosureSubsts<'tcx>),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
/// The `!` operator for logical inversion
Not,
/// The `-` operator for negation
- Neg
+ Neg,
}
-impl<H:Hair> Debug for Rvalue<H> {
+impl<'tcx> Debug for Rvalue<'tcx> {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
use self::Rvalue::*;
Box(ref t) => write!(fmt, "Box {:?}", t),
Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>({:?})", kind, lvs),
InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm),
- Slice { ref input, from_start, from_end } => write!(fmt, "{:?}[{:?}..-{:?}]",
- input, from_start, from_end),
+ Slice { ref input, from_start, from_end } =>
+ write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end),
}
}
}
///////////////////////////////////////////////////////////////////////////
// Constants
+//
+// Two constants are equal if they are the same constant. Note that
+// this does not necessarily mean that they are "==" in Rust -- in
+// particular one must be wary of `NaN`!
#[derive(Clone, Debug, PartialEq)]
-pub struct Constant<H:Hair> {
- pub span: H::Span,
- pub kind: ConstantKind<H>
-}
-
-#[derive(Clone, Debug, PartialEq)]
-pub enum ConstantKind<H:Hair> {
- Literal(Literal<H>),
- Aggregate(AggregateKind<H>, Vec<Constant<H>>),
- Call(Box<Constant<H>>, Vec<Constant<H>>),
- Cast(Box<Constant<H>>, H::Ty),
- Repeat(Box<Constant<H>>, Box<Constant<H>>),
- Ref(BorrowKind, Box<Constant<H>>),
- BinaryOp(BinOp, Box<Constant<H>>, Box<Constant<H>>),
- UnaryOp(UnOp, Box<Constant<H>>),
- Projection(Box<ConstantProjection<H>>)
+pub struct Constant<'tcx> {
+ pub span: Span,
+ pub ty: Ty<'tcx>,
+ pub literal: Literal<'tcx>,
}
-pub type ConstantProjection<H> =
- Projection<H,Constant<H>,Constant<H>>;
-
#[derive(Clone, Debug, PartialEq)]
-pub enum Literal<H:Hair> {
- Item { def_id: H::DefId, substs: H::Substs },
- Projection { projection: H::Projection },
- Int { bits: IntegralBits, value: i64 },
- Uint { bits: IntegralBits, value: u64 },
- Float { bits: FloatBits, value: f64 },
- Char { c: char },
- Bool { value: bool },
- Bytes { value: H::Bytes },
- String { value: H::InternedString },
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
-pub enum IntegralBits {
- B8, B16, B32, B64, BSize
-}
-
-#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
-pub enum FloatBits {
- F32, F64
+pub enum Literal<'tcx> {
+ Item {
+ def_id: DefId,
+ substs: &'tcx Substs<'tcx>,
+ },
+ Value {
+ value: ConstVal,
+ },
}
use tcx::Cx;
use tcx::pattern::PatNode;
-use tcx::rustc::middle::region::{BlockRemainder, CodeExtentData};
-use tcx::rustc_front::hir;
-use tcx::syntax::ast;
-use tcx::syntax::ptr::P;
use tcx::to_ref::ToRef;
+use rustc::middle::region::{BlockRemainder, CodeExtentData};
+use rustc_front::hir;
+use syntax::ast;
+use syntax::ptr::P;
-impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Block {
- type Output = Block<Cx<'a,'tcx>>;
+impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
+ type Output = Block<'tcx>;
- fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Block<Cx<'a,'tcx>> {
+ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Block<'tcx> {
// We have to eagerly translate the "spine" of the statements
// in order to get the lexical scoping correctly.
let stmts = mirror_stmts(cx, self.id, self.stmts.iter().enumerate());
extent: cx.tcx.region_maps.node_extent(self.id),
span: self.span,
stmts: stmts,
- expr: self.expr.to_ref()
+ expr: self.expr.to_ref(),
}
}
}
-impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Stmt {
- type Output = Stmt<Cx<'a,'tcx>>;
+impl<'tcx> Mirror<'tcx> for &'tcx hir::Stmt {
+ type Output = Stmt<'tcx>;
- fn make_mirror(self, _cx: &mut Cx<'a,'tcx>) -> Stmt<Cx<'a,'tcx>> {
+ fn make_mirror<'a>(self, _cx: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> {
// In order to get the scoping correct, we eagerly mirror
// statements when we translate the enclosing block, so we
// should in fact never get to this point.
}
}
-fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
- block_id: ast::NodeId,
- mut stmts: STMTS)
- -> Vec<StmtRef<Cx<'a,'tcx>>>
- where STMTS: Iterator<Item=(usize, &'tcx P<hir::Stmt>)>
+fn mirror_stmts<'a, 'tcx: 'a, STMTS>(cx: &mut Cx<'a, 'tcx>,
+ block_id: ast::NodeId,
+ mut stmts: STMTS)
+ -> Vec<StmtRef<'tcx>>
+ where STMTS: Iterator<Item = (usize, &'tcx P<hir::Stmt>)>
{
let mut result = vec![];
while let Some((index, stmt)) = stmts.next() {
hir::DeclLocal(ref local) => {
let remainder_extent = CodeExtentData::Remainder(BlockRemainder {
block: block_id,
- first_statement_index: index as u32
+ first_statement_index: index as u32,
});
let remainder_extent =
cx.tcx.region_maps.lookup_code_extent(remainder_extent);
// they are within the scope of this let:
let following_stmts = mirror_stmts(cx, block_id, stmts);
- result.push(
- StmtRef::Mirror(
- Box::new(Stmt {
- span: stmt.span,
- kind: StmtKind::Let {
- remainder_scope: remainder_extent,
- init_scope: cx.tcx.region_maps.node_extent(id),
- pattern: PatNode::irrefutable(&local.pat).to_ref(),
- initializer: local.init.to_ref(),
- stmts: following_stmts
- }
- })));
+ result.push(StmtRef::Mirror(Box::new(Stmt {
+ span: stmt.span,
+ kind: StmtKind::Let {
+ remainder_scope: remainder_extent,
+ init_scope: cx.tcx.region_maps.node_extent(id),
+ pattern: PatNode::irrefutable(&local.pat).to_ref(),
+ initializer: local.init.to_ref(),
+ stmts: following_stmts,
+ },
+ })));
return result;
}
return result;
}
-pub fn to_expr_ref<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- block: &'tcx hir::Block)
- -> ExprRef<Cx<'a, 'tcx>> {
+pub fn to_expr_ref<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, block: &'tcx hir::Block) -> ExprRef<'tcx> {
let block_ty = cx.tcx.node_id_to_type(block.id);
let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id);
let expr = Expr {
ty: block_ty,
temp_lifetime: temp_lifetime,
span: block.span,
- kind: ExprKind::Block { body: block }
+ kind: ExprKind::Block { body: block },
};
expr.to_ref()
}
use tcx::Cx;
use tcx::block;
use tcx::pattern::PatNode;
-use tcx::rustc::front::map;
-use tcx::rustc::middle::def;
-use tcx::rustc::middle::def_id::DefId;
-use tcx::rustc::middle::region::CodeExtent;
-use tcx::rustc::middle::pat_util;
-use tcx::rustc::middle::ty::{self, Ty};
-use tcx::rustc_front::hir;
-use tcx::rustc_front::util as hir_util;
-use tcx::syntax::codemap::Span;
-use tcx::syntax::parse::token;
-use tcx::syntax::ptr::P;
use tcx::to_ref::ToRef;
-
-impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
- type Output = Expr<Cx<'a,'tcx>>;
-
- fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Expr<Cx<'a,'tcx>> {
+use rustc::front::map;
+use rustc::middle::const_eval;
+use rustc::middle::def;
+use rustc::middle::region::CodeExtent;
+use rustc::middle::pat_util;
+use rustc::middle::ty::{self, Ty};
+use rustc_front::hir;
+use rustc_front::util as hir_util;
+use syntax::ext::mtwt;
+use syntax::parse::token;
+use syntax::ptr::P;
+
+impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
+ type Output = Expr<'tcx>;
+
+ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)!
let kind = match self.node {
// Here comes the interesting stuff:
-
hir::ExprMethodCall(_, _, ref args) => {
// Rewrite a.b(c) into UFCS form like Trait::b(a, c)
let expr = method_callee(cx, self, ty::MethodCall::expr(self.id));
.collect();
ExprKind::Call {
fun: expr.to_ref(),
- args: args
+ args: args,
}
}
hir::ExprAddrOf(mutbl, ref expr) => {
let region = match expr_ty.sty {
ty::TyRef(r, _) => r,
- _ => cx.tcx.sess.span_bug(expr.span, "type of & not region")
+ _ => cx.tcx.sess.span_bug(expr.span, "type of & not region"),
};
- ExprKind::Borrow { region: *region,
- borrow_kind: to_borrow_kind(mutbl),
- arg: expr.to_ref() }
+ ExprKind::Borrow {
+ region: *region,
+ borrow_kind: to_borrow_kind(mutbl),
+ arg: expr.to_ref(),
+ }
}
hir::ExprBlock(ref blk) => {
- ExprKind::Block {
- body: &**blk
- }
+ ExprKind::Block { body: &**blk }
}
hir::ExprAssign(ref lhs, ref rhs) => {
}
}
- hir::ExprLit(ref lit) => {
- let literal = convert_literal(cx, self.span, expr_ty, lit);
- ExprKind::Literal { literal: literal }
+ hir::ExprLit(..) => {
+ let value = const_eval::eval_const_expr(cx.tcx, self);
+ ExprKind::Literal { literal: Literal::Value { value: value } }
}
hir::ExprBinary(op, ref lhs, ref rhs) => {
// FIXME overflow
match op.node {
hir::BinOp_::BiAnd => {
- ExprKind::LogicalOp { op: LogicalOp::And,
- lhs: lhs.to_ref(),
- rhs: rhs.to_ref() }
+ ExprKind::LogicalOp {
+ op: LogicalOp::And,
+ lhs: lhs.to_ref(),
+ rhs: rhs.to_ref(),
+ }
}
hir::BinOp_::BiOr => {
- ExprKind::LogicalOp { op: LogicalOp::Or,
- lhs: lhs.to_ref(),
- rhs: rhs.to_ref() }
+ ExprKind::LogicalOp {
+ op: LogicalOp::Or,
+ lhs: lhs.to_ref(),
+ rhs: rhs.to_ref(),
+ }
}
_ => {
let op = bin_op(op.node);
- ExprKind::Binary { op: op,
- lhs: lhs.to_ref(),
- rhs: rhs.to_ref() }
+ ExprKind::Binary {
+ op: op,
+ lhs: lhs.to_ref(),
+ rhs: rhs.to_ref(),
+ }
}
}
}
overloaded_lvalue(cx, self, ty::MethodCall::expr(self.id),
PassArgs::ByValue, lhs.to_ref(), vec![index])
} else {
- ExprKind::Index { lhs: lhs.to_ref(),
- index: index.to_ref() }
+ ExprKind::Index {
+ lhs: lhs.to_ref(),
+ index: index.to_ref(),
+ }
}
}
}
}
- hir::ExprUnary(hir::UnOp::UnUniq, ref arg) => {
- assert!(!cx.tcx.is_method_call(self.id));
- ExprKind::Box { place: None, value: arg.to_ref() }
- }
-
hir::ExprUnary(op, ref arg) => {
if cx.tcx.is_method_call(self.id) {
overloaded_operator(cx, self, ty::MethodCall::expr(self.id),
let op = match op {
hir::UnOp::UnNot => UnOp::Not,
hir::UnOp::UnNeg => UnOp::Neg,
- hir::UnOp::UnUniq | hir::UnOp::UnDeref => {
+ hir::UnOp::UnDeref => {
cx.tcx.sess.span_bug(
self.span,
- &format!("operator should have been handled elsewhere {:?}", op));
+ "UnDeref should have been handled elsewhere");
}
};
- ExprKind::Unary { op: op, arg: arg.to_ref() }
+ ExprKind::Unary {
+ op: op,
+ arg: arg.to_ref(),
+ }
}
}
ty::TyClosure(def_id, ref substs) => (def_id, substs),
_ => {
cx.tcx.sess.span_bug(self.span,
- &format!("closure expr w/o closure type: {:?}",
- closure_ty));
+ &format!("closure expr w/o closure type: {:?}",
+ closure_ty));
}
};
let upvars = cx.tcx.with_freevars(self.id, |freevars| {
let (adt_def, substs) = match range_ty.sty {
ty::TyStruct(adt_def, substs) => (adt_def, substs),
_ => {
- cx.tcx.sess.span_bug(
- self.span,
- &format!("unexpanded ast"));
+ cx.tcx.sess.span_bug(self.span, &format!("unexpanded ast"));
}
};
let field_expr_ref = |s: &'tcx P<hir::Expr>, nm: &str| {
- FieldExprRef { name: Field::Named(token::intern(nm)),
- expr: s.to_ref() }
+ FieldExprRef {
+ name: Field::Named(token::intern(nm)),
+ expr: s.to_ref(),
+ }
};
let start_field = start.as_ref()
.into_iter()
.map(|e| field_expr_ref(e, "end"));
- ExprKind::Adt { adt_def: adt_def,
- variant_index: 0,
- substs: substs,
- fields: start_field.chain(end_field).collect(),
- base: None }
+ ExprKind::Adt {
+ adt_def: adt_def,
+ variant_index: 0,
+ substs: substs,
+ fields: start_field.chain(end_field).collect(),
+ base: None,
+ }
}
hir::ExprPath(..) => {
// Now comes the rote stuff:
- hir::ExprParen(ref p) =>
- ExprKind::Paren { arg: p.to_ref() },
hir::ExprRepeat(ref v, ref c) =>
ExprKind::Repeat { value: v.to_ref(), count: c.to_ref() },
hir::ExprRet(ref v) =>
hir::ExprLoop(ref body, _) =>
ExprKind::Loop { condition: None,
body: block::to_expr_ref(cx, body) },
- hir::ExprField(ref source, ident) =>
+ hir::ExprField(ref source, name) =>
ExprKind::Field { lhs: source.to_ref(),
- name: Field::Named(ident.node.name) },
- hir::ExprTupField(ref source, ident) =>
+ name: Field::Named(name.node) },
+ hir::ExprTupField(ref source, index) =>
ExprKind::Field { lhs: source.to_ref(),
- name: Field::Indexed(ident.node) },
+ name: Field::Indexed(index.node) },
hir::ExprCast(ref source, _) =>
ExprKind::Cast { source: source.to_ref() },
- hir::ExprBox(ref place, ref value) =>
- ExprKind::Box { place: place.to_ref(), value: value.to_ref() },
+ hir::ExprBox(ref value) =>
+ ExprKind::Box { value: value.to_ref() },
hir::ExprVec(ref fields) =>
ExprKind::Vec { fields: fields.to_ref() },
hir::ExprTup(ref fields) =>
// Now apply adjustments, if any.
match cx.tcx.tables.borrow().adjustments.get(&self.id) {
- None => { }
+ None => {}
Some(&ty::adjustment::AdjustReifyFnPointer) => {
let adjusted_ty = cx.tcx.expr_ty_adjusted(self);
expr = Expr {
temp_lifetime: temp_lifetime,
ty: adjusted_ty,
span: self.span,
- kind: kind
+ kind: kind,
};
}
temp_lifetime: temp_lifetime,
ty: target,
span: self.span,
- kind: ExprKind::Unsize { source: expr.to_ref() }
+ kind: ExprKind::Unsize { source: expr.to_ref() },
};
} else if let Some(autoref) = adj.autoref {
let adjusted_ty = expr.ty.adjust_for_autoref(cx.tcx, Some(autoref));
temp_lifetime: temp_lifetime,
ty: adjusted_ty,
span: self.span,
- kind: ExprKind::Borrow { region: *r,
- borrow_kind: to_borrow_kind(m),
- arg: expr.to_ref() }
+ kind: ExprKind::Borrow {
+ region: *r,
+ borrow_kind: to_borrow_kind(m),
+ arg: expr.to_ref(),
+ },
};
}
ty::adjustment::AutoUnsafe(m) => {
temp_lifetime: temp_lifetime,
ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }),
span: self.span,
- kind: ExprKind::Borrow { region: *region,
- borrow_kind: to_borrow_kind(m),
- arg: expr.to_ref() }
+ kind: ExprKind::Borrow {
+ region: *region,
+ borrow_kind: to_borrow_kind(m),
+ arg: expr.to_ref(),
+ },
};
expr = Expr {
temp_lifetime: temp_lifetime,
ty: adjusted_ty,
span: self.span,
- kind: ExprKind::Cast { source: expr.to_ref() }
+ kind: ExprKind::Cast { source: expr.to_ref() },
};
}
}
temp_lifetime: temp_lifetime,
ty: expr.ty,
span: self.span,
- kind: ExprKind::Scope { extent: expr_extent,
- value: expr.to_ref() }
+ kind: ExprKind::Scope {
+ extent: expr_extent,
+ value: expr.to_ref(),
+ },
};
// Finally, create a destruction scope, if any.
temp_lifetime: temp_lifetime,
ty: expr.ty,
span: self.span,
- kind: ExprKind::Scope { extent: extent, value: expr.to_ref() }
+ kind: ExprKind::Scope {
+ extent: extent,
+ value: expr.to_ref(),
+ },
};
}
}
}
-fn method_callee<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- expr: &hir::Expr,
- method_call: ty::MethodCall)
- -> Expr<Cx<'a,'tcx>> {
+fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
+ expr: &hir::Expr,
+ method_call: ty::MethodCall)
+ -> Expr<'tcx> {
let tables = cx.tcx.tables.borrow();
let callee = &tables.method_map[&method_call];
let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
literal: Literal::Item {
def_id: callee.def_id,
substs: callee.substs,
- }
- }
+ },
+ },
}
}
}
}
-fn convert_literal<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- expr_span: Span,
- expr_ty: Ty<'tcx>,
- literal: &hir::Lit)
- -> Literal<Cx<'a,'tcx>>
-{
- use repr::IntegralBits::*;
- match (&literal.node, &expr_ty.sty) {
- (&hir::LitStr(ref text, _), _) =>
- Literal::String { value: text.clone() },
- (&hir::LitByteStr(ref bytes), _) =>
- Literal::Bytes { value: bytes.clone() },
- (&hir::LitByte(c), _) =>
- Literal::Uint { bits: B8, value: c as u64 },
- (&hir::LitChar(c), _) =>
- Literal::Char { c: c },
- (&hir::LitInt(v, _), &ty::TyUint(hir::TyU8)) =>
- Literal::Uint { bits: B8, value: v },
- (&hir::LitInt(v, _), &ty::TyUint(hir::TyU16)) =>
- Literal::Uint { bits: B16, value: v },
- (&hir::LitInt(v, _), &ty::TyUint(hir::TyU32)) =>
- Literal::Uint { bits: B32, value: v },
- (&hir::LitInt(v, _), &ty::TyUint(hir::TyU64)) =>
- Literal::Uint { bits: B64, value: v },
- (&hir::LitInt(v, _), &ty::TyUint(hir::TyUs)) =>
- Literal::Uint { bits: BSize, value: v },
- (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI8)) =>
- Literal::Int { bits: B8, value: -(v as i64) },
- (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI16)) =>
- Literal::Int { bits: B16, value: -(v as i64) },
- (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI32)) =>
- Literal::Int { bits: B32, value: -(v as i64) },
- (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyI64)) =>
- Literal::Int { bits: B64, value: -(v as i64) },
- (&hir::LitInt(v, hir::SignedIntLit(_, hir::Sign::Minus)), &ty::TyInt(hir::TyIs)) =>
- Literal::Int { bits: BSize, value: -(v as i64) },
- (&hir::LitInt(v, _), &ty::TyInt(hir::TyI8)) =>
- Literal::Int { bits: B8, value: v as i64 },
- (&hir::LitInt(v, _), &ty::TyInt(hir::TyI16)) =>
- Literal::Int { bits: B16, value: v as i64 },
- (&hir::LitInt(v, _), &ty::TyInt(hir::TyI32)) =>
- Literal::Int { bits: B32, value: v as i64 },
- (&hir::LitInt(v, _), &ty::TyInt(hir::TyI64)) =>
- Literal::Int { bits: B64, value: v as i64 },
- (&hir::LitInt(v, _), &ty::TyInt(hir::TyIs)) =>
- Literal::Int { bits: BSize, value: v as i64 },
- (&hir::LitFloat(ref v, _), &ty::TyFloat(hir::TyF32)) |
- (&hir::LitFloatUnsuffixed(ref v), &ty::TyFloat(hir::TyF32)) =>
- Literal::Float { bits: FloatBits::F32, value: v.parse::<f64>().unwrap() },
- (&hir::LitFloat(ref v, _), &ty::TyFloat(hir::TyF64)) |
- (&hir::LitFloatUnsuffixed(ref v), &ty::TyFloat(hir::TyF64)) =>
- Literal::Float { bits: FloatBits::F64, value: v.parse::<f64>().unwrap() },
- (&hir::LitBool(v), _) =>
- Literal::Bool { value: v },
- (ref l, ref t) =>
- cx.tcx.sess.span_bug(
- expr_span,
- &format!("Invalid literal/type combination: {:?},{:?}", l, t))
- }
-}
-
-fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm<Cx<'a,'tcx>> {
+fn convert_arm<'a, 'tcx: 'a>(cx: &Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
let map = if arm.pats.len() == 1 {
None
} else {
let mut map = FnvHashMap();
- pat_util::pat_bindings(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| {
- map.insert(path.node, p_id);
+ pat_util::pat_bindings_hygienic(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| {
+ map.insert(mtwt::resolve(path.node), p_id);
});
Some(Rc::new(map))
};
- Arm { patterns: arm.pats.iter().map(|p| PatNode::new(p, map.clone()).to_ref()).collect(),
- guard: arm.guard.to_ref(),
- body: arm.body.to_ref() }
+ Arm {
+ patterns: arm.pats.iter().map(|p| PatNode::new(p, map.clone()).to_ref()).collect(),
+ guard: arm.guard.to_ref(),
+ body: arm.body.to_ref(),
+ }
}
-fn convert_path_expr<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- expr: &'tcx hir::Expr)
- -> ExprKind<Cx<'a,'tcx>>
-{
+fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> {
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
match cx.tcx.def_map.borrow()[&expr.id].full_def() {
def::DefVariant(_, def_id, false) |
}
}
-fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- expr: &'tcx hir::Expr,
- def: def::Def)
- -> ExprKind<Cx<'a,'tcx>>
-{
+fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
+ expr: &'tcx hir::Expr,
+ def: def::Def)
+ -> ExprKind<'tcx> {
let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
match def {
- def::DefLocal(node_id) => {
+ def::DefLocal(_, node_id) => {
ExprKind::VarRef {
id: node_id,
}
}
- def::DefUpvar(id_var, index, closure_expr_id) => {
+ def::DefUpvar(_, id_var, index, closure_expr_id) => {
debug!("convert_var(upvar({:?}, {:?}, {:?}))", id_var, index, closure_expr_id);
let var_ty = cx.tcx.node_id_to_type(id_var);
};
// FIXME free regions in closures are not right
- let closure_ty =
- cx.tcx.node_id_to_type(closure_expr_id);
+ let closure_ty = cx.tcx.node_id_to_type(closure_expr_id);
// FIXME we're just hard-coding the idea that the
// signature will be &self or &mut self and hence will
// have a bound region with number 0
- let region =
- ty::Region::ReFree(
- ty::FreeRegion {
- scope: cx.tcx.region_maps.node_extent(body_id),
- bound_region: ty::BoundRegion::BrAnon(0)
- });
- let region =
- cx.tcx.mk_region(region);
-
- let self_expr = match cx.tcx.closure_kind(DefId::local(closure_expr_id)) {
+ let region = ty::Region::ReFree(ty::FreeRegion {
+ scope: cx.tcx.region_maps.node_extent(body_id),
+ bound_region: ty::BoundRegion::BrAnon(0),
+ });
+ let region = cx.tcx.mk_region(region);
+
+ let self_expr = match cx.tcx.closure_kind(cx.tcx.map.local_def_id(closure_expr_id)) {
ty::ClosureKind::FnClosureKind => {
let ref_closure_ty =
cx.tcx.mk_ref(region,
ty: closure_ty,
temp_lifetime: temp_lifetime,
span: expr.span,
- kind: ExprKind::SelfRef
+ kind: ExprKind::SelfRef,
}
}
};
// at this point we have `self.n`, which loads up the upvar
- let field_kind =
- ExprKind::Field { lhs: self_expr.to_ref(),
- name: Field::Indexed(index) };
+ let field_kind = ExprKind::Field {
+ lhs: self_expr.to_ref(),
+ name: Field::Indexed(index),
+ };
// ...but the upvar might be an `&T` or `&mut T` capture, at which
// point we need an implicit deref
- let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr_id };
+ let upvar_id = ty::UpvarId {
+ var_id: id_var,
+ closure_expr_id: closure_expr_id,
+ };
let upvar_capture = match cx.tcx.upvar_capture(upvar_id) {
Some(c) => c,
None => {
}
}
- _ => cx.tcx.sess.span_bug(expr.span, "type of & not region")
+ _ => cx.tcx.sess.span_bug(expr.span, "type of & not region"),
}
}
hir::BinOp_::BiNe => BinOp::Ne,
hir::BinOp_::BiGe => BinOp::Ge,
hir::BinOp_::BiGt => BinOp::Gt,
- _ => panic!("no equivalent for ast binop {:?}", op)
+ _ => panic!("no equivalent for ast binop {:?}", op),
}
}
enum PassArgs {
ByValue,
- ByRef
+ ByRef,
}
-fn overloaded_operator<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- expr: &'tcx hir::Expr,
- method_call: ty::MethodCall,
- pass_args: PassArgs,
- receiver: ExprRef<Cx<'a,'tcx>>,
- args: Vec<&'tcx P<hir::Expr>>)
- -> ExprKind<Cx<'a,'tcx>>
-{
+fn overloaded_operator<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
+ expr: &'tcx hir::Expr,
+ method_call: ty::MethodCall,
+ pass_args: PassArgs,
+ receiver: ExprRef<'tcx>,
+ args: Vec<&'tcx P<hir::Expr>>)
+ -> ExprKind<'tcx> {
// the receiver has all the adjustments that are needed, so we can
// just push a reference to it
let mut argrefs = vec![receiver];
// operator, we have to gin up the autorefs (but by value is easy)
match pass_args {
PassArgs::ByValue => {
- argrefs.extend(
- args.iter()
- .map(|arg| arg.to_ref()))
+ argrefs.extend(args.iter().map(|arg| arg.to_ref()))
}
PassArgs::ByRef => {
}
}
-fn overloaded_lvalue<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- expr: &'tcx hir::Expr,
- method_call: ty::MethodCall,
- pass_args: PassArgs,
- receiver: ExprRef<Cx<'a,'tcx>>,
- args: Vec<&'tcx P<hir::Expr>>)
- -> ExprKind<Cx<'a,'tcx>>
-{
+fn overloaded_lvalue<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
+ expr: &'tcx hir::Expr,
+ method_call: ty::MethodCall,
+ pass_args: PassArgs,
+ receiver: ExprRef<'tcx>,
+ args: Vec<&'tcx P<hir::Expr>>)
+ -> ExprKind<'tcx> {
// For an overloaded *x or x[y] expression of type T, the method
// call returns an &T and we must add the deref so that the types
// line up (this is because `*x` and `x[y]` represent lvalues):
ExprKind::Deref { arg: ref_expr.to_ref() }
}
-fn capture_freevar<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- closure_expr: &'tcx hir::Expr,
- freevar: &ty::Freevar,
- freevar_ty: Ty<'tcx>)
- -> ExprRef<Cx<'a,'tcx>> {
- let id_var = freevar.def.def_id().node;
- let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id };
+fn capture_freevar<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
+ closure_expr: &'tcx hir::Expr,
+ freevar: &ty::Freevar,
+ freevar_ty: Ty<'tcx>)
+ -> ExprRef<'tcx> {
+ let id_var = freevar.def.var_id();
+ let upvar_id = ty::UpvarId {
+ var_id: id_var,
+ closure_expr_id: closure_expr.id,
+ };
let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap();
let temp_lifetime = cx.tcx.region_maps.temporary_scope(closure_expr.id);
let var_ty = cx.tcx.node_id_to_type(id_var);
- let captured_var = Expr { temp_lifetime: temp_lifetime,
- ty: var_ty,
- span: closure_expr.span,
- kind: convert_var(cx, closure_expr, freevar.def) };
+ let captured_var = Expr {
+ temp_lifetime: temp_lifetime,
+ ty: var_ty,
+ span: closure_expr.span,
+ kind: convert_var(cx, closure_expr, freevar.def),
+ };
match upvar_capture {
ty::UpvarCapture::ByValue => {
captured_var.to_ref()
}
}
-fn loop_label<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
- expr: &'tcx hir::Expr)
- -> CodeExtent
-{
+fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> CodeExtent {
match cx.tcx.def_map.borrow().get(&expr.id).map(|d| d.full_def()) {
Some(def::DefLabel(loop_id)) => cx.tcx.region_maps.node_extent(loop_id),
d => {
- cx.tcx.sess.span_bug(
- expr.span,
- &format!("loop scope resolved to {:?}", d));
+ cx.tcx.sess.span_bug(expr.span, &format!("loop scope resolved to {:?}", d));
}
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+/*!
+ * This module contains the code to convert from the wacky tcx data
+ * structures into the hair. The `builder` is generally ignorant of
+ * the tcx etc, and instead goes through the `Cx` for most of its
+ * work.
+ */
+
use hair::*;
use repr::*;
-use std::fmt::{Debug, Formatter, Error};
-use std::hash::{Hash, Hasher};
-use std::rc::Rc;
-
-use self::rustc::middle::def_id::DefId;
-use self::rustc::middle::infer::InferCtxt;
-use self::rustc::middle::region::CodeExtent;
-use self::rustc::middle::subst::{self, Subst, Substs};
-use self::rustc::middle::ty::{self, Ty};
-use self::rustc_front::hir;
-use self::syntax::ast;
-use self::syntax::codemap::Span;
-use self::syntax::parse::token::{self, special_idents, InternedString};
-
-extern crate rustc;
-extern crate rustc_front;
-extern crate syntax;
+
+use rustc::middle::const_eval::ConstVal;
+use rustc::middle::def_id::DefId;
+use rustc::middle::infer::InferCtxt;
+use rustc::middle::subst::{Subst, Substs};
+use rustc::middle::ty::{self, Ty};
+use syntax::codemap::Span;
+use syntax::parse::token::{self, special_idents};
#[derive(Copy, Clone)]
-pub struct Cx<'a,'tcx:'a> {
- pub tcx: &'a ty::ctxt<'tcx>,
- pub infcx: &'a InferCtxt<'a,'tcx>,
+pub struct Cx<'a, 'tcx: 'a> {
+ tcx: &'a ty::ctxt<'tcx>,
+ infcx: &'a InferCtxt<'a, 'tcx>,
}
impl<'a,'tcx> Cx<'a,'tcx> {
- pub fn new(infcx: &'a InferCtxt<'a,'tcx>) -> Cx<'a,'tcx> {
- Cx { tcx: infcx.tcx, infcx: infcx }
+ pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Cx<'a, 'tcx> {
+ Cx {
+ tcx: infcx.tcx,
+ infcx: infcx,
+ }
}
}
pub use self::pattern::PatNode;
-impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
- type VarId = ast::NodeId;
- type DefId = DefId;
- type AdtDef = ty::AdtDef<'tcx>;
- type Name = ast::Name;
- type Ident = ast::Ident;
- type InternedString = InternedString;
- type Bytes = Rc<Vec<u8>>;
- type Span = Span;
- type Projection = ty::ProjectionTy<'tcx>;
- type Substs = &'tcx subst::Substs<'tcx>;
- type ClosureSubsts = &'tcx ty::ClosureSubsts<'tcx>;
- type Ty = Ty<'tcx>;
- type Region = ty::Region;
- type CodeExtent = CodeExtent;
- type Pattern = PatNode<'tcx>;
- type Expr = &'tcx hir::Expr;
- type Stmt = &'tcx hir::Stmt;
- type Block = &'tcx hir::Block;
- type InlineAsm = &'tcx hir::InlineAsm;
-
- fn unit_ty(&mut self) -> Ty<'tcx> {
+impl<'a,'tcx:'a> Cx<'a, 'tcx> {
+ /// Normalizes `ast` into the appropriate `mirror` type.
+ pub fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
+ ast.make_mirror(self)
+ }
+
+ pub fn unit_ty(&mut self) -> Ty<'tcx> {
self.tcx.mk_nil()
}
- fn usize_ty(&mut self) -> Ty<'tcx> {
+ pub fn usize_ty(&mut self) -> Ty<'tcx> {
self.tcx.types.usize
}
- fn bool_ty(&mut self) -> Ty<'tcx> {
+ pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
+ Literal::Value { value: ConstVal::Uint(value as u64) }
+ }
+
+ pub fn bool_ty(&mut self) -> Ty<'tcx> {
self.tcx.types.bool
}
- fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<Self> {
+ pub fn true_literal(&mut self) -> Literal<'tcx> {
+ Literal::Value { value: ConstVal::Bool(true) }
+ }
+
+ pub fn false_literal(&mut self) -> Literal<'tcx> {
+ Literal::Value { value: ConstVal::Bool(false) }
+ }
+
+ pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
self.cmp_method_ref(eq_def_id, "eq", ty)
}
- fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<Self> {
+ pub fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
let ord_def_id = self.tcx.lang_items.ord_trait().unwrap();
self.cmp_method_ref(ord_def_id, "le", ty)
}
- fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
+ pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
adt_def.variants.len()
}
- fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec<Field<Self>> {
+ pub fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec<Field> {
adt_def.variants[variant_index]
.fields
.iter()
.collect()
}
- fn needs_drop(&mut self, ty: Ty<'tcx>, span: Self::Span) -> bool {
+ pub fn needs_drop(&mut self, ty: Ty<'tcx>, span: Span) -> bool {
if self.infcx.type_moves_by_default(ty, span) {
// FIXME(#21859) we should do an add'l check here to determine if
// any dtor will execute, but the relevant fn
}
}
- fn span_bug(&mut self, span: Self::Span, message: &str) -> ! {
+ pub fn span_bug(&mut self, span: Span, message: &str) -> ! {
self.tcx.sess.span_bug(span, message)
}
-}
-impl<'a,'tcx:'a> Cx<'a,'tcx> {
+ pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
+ self.tcx
+ }
+
fn cmp_method_ref(&mut self,
trait_def_id: DefId,
method_name: &str,
arg_ty: Ty<'tcx>)
- -> ItemRef<Cx<'a,'tcx>> {
+ -> ItemRef<'tcx> {
let method_name = token::intern(method_name);
let substs = Substs::new_trait(vec![arg_ty], vec![], arg_ty);
for trait_item in self.tcx.trait_items(trait_def_id).iter() {
}
}
ty::ImplOrTraitItem::ConstTraitItem(..) |
- ty::ImplOrTraitItem::TypeTraitItem(..) => {
- }
+ ty::ImplOrTraitItem::TypeTraitItem(..) => {}
}
}
- self.tcx.sess.bug(
- &format!("found no method `{}` in `{:?}`", method_name, trait_def_id));
- }
-}
-
-// We only need this impl so that we do deriving for things that are
-// defined relative to the `Hair` trait. See `Hair` trait for more
-// details.
-impl<'a,'tcx> PartialEq for Cx<'a,'tcx> {
- fn eq(&self, _: &Cx<'a,'tcx>) -> bool {
- panic!("Cx should never ACTUALLY be compared for equality")
- }
-}
-
-impl<'a,'tcx> Eq for Cx<'a,'tcx> { }
-
-impl<'a,'tcx> Hash for Cx<'a,'tcx> {
- fn hash<H: Hasher>(&self, _: &mut H) {
- panic!("Cx should never ACTUALLY be hashed")
- }
-}
-
-impl<'a,'tcx> Debug for Cx<'a,'tcx> {
- fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
- write!(fmt, "Tcx")
+ self.tcx.sess.bug(&format!("found no method `{}` in `{:?}`", method_name, trait_def_id));
}
}
mod expr;
mod pattern;
mod to_ref;
-
use rustc_data_structures::fnv::FnvHashMap;
use std::rc::Rc;
use tcx::Cx;
-use tcx::rustc::middle::const_eval::lookup_const_by_id;
-use tcx::rustc::middle::def;
-use tcx::rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
-use tcx::rustc::middle::ty::{self, Ty};
-use tcx::rustc_front::hir;
-use tcx::syntax::ast;
-use tcx::syntax::ptr::P;
use tcx::to_ref::ToRef;
+use rustc::middle::const_eval;
+use rustc::middle::def;
+use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
+use rustc::middle::subst::Substs;
+use rustc::middle::ty::{self, Ty};
+use rustc_front::hir;
+use syntax::ast;
+use syntax::ext::mtwt;
+use syntax::ptr::P;
/// When there are multiple patterns in a single arm, each one has its
/// own node-ids for the bindings. References to the variables always
#[derive(Clone, Debug)]
pub struct PatNode<'tcx> {
pat: &'tcx hir::Pat,
- binding_map: Option<Rc<FnvHashMap<ast::Ident, ast::NodeId>>>
+ binding_map: Option<Rc<FnvHashMap<ast::Name, ast::NodeId>>>,
}
impl<'tcx> PatNode<'tcx> {
pub fn new(pat: &'tcx hir::Pat,
- binding_map: Option<Rc<FnvHashMap<ast::Ident, ast::NodeId>>>)
+ binding_map: Option<Rc<FnvHashMap<ast::Name, ast::NodeId>>>)
-> PatNode<'tcx> {
PatNode {
pat: pat,
}
}
- pub fn irrefutable(pat: &'tcx hir::Pat)
- -> PatNode<'tcx> {
+ pub fn irrefutable(pat: &'tcx hir::Pat) -> PatNode<'tcx> {
PatNode::new(pat, None)
}
- fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<Cx<'a,'tcx>> {
+ fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<'tcx> {
PatNode::new(pat, self.binding_map.clone()).to_ref()
}
- fn pat_refs<'a>(&self, pats: &'tcx Vec<P<hir::Pat>>) -> Vec<PatternRef<Cx<'a,'tcx>>> {
+ fn pat_refs<'a>(&self, pats: &'tcx Vec<P<hir::Pat>>) -> Vec<PatternRef<'tcx>> {
pats.iter().map(|p| self.pat_ref(p)).collect()
}
- fn opt_pat_ref<'a>(&self, pat: &'tcx Option<P<hir::Pat>>) -> Option<PatternRef<Cx<'a,'tcx>>> {
+ fn opt_pat_ref<'a>(&self, pat: &'tcx Option<P<hir::Pat>>) -> Option<PatternRef<'tcx>> {
pat.as_ref().map(|p| self.pat_ref(p))
}
prefix: &'tcx Vec<P<hir::Pat>>,
slice: &'tcx Option<P<hir::Pat>>,
suffix: &'tcx Vec<P<hir::Pat>>)
- -> PatternKind<Cx<'a,'tcx>>
- {
+ -> PatternKind<'tcx> {
match ty.sty {
ty::TySlice(..) =>
// matching a slice or fixed-length array
}
_ => {
- cx.tcx.sess.span_bug(
- self.pat.span,
- "unexpanded macro or bad constant etc");
+ cx.tcx.sess.span_bug(self.pat.span, "unexpanded macro or bad constant etc");
}
}
}
fn variant_or_leaf<'a>(&self,
cx: &mut Cx<'a, 'tcx>,
- subpatterns: Vec<FieldPatternRef<Cx<'a,'tcx>>>)
- -> PatternKind<Cx<'a,'tcx>>
- {
+ subpatterns: Vec<FieldPatternRef<'tcx>>)
+ -> PatternKind<'tcx> {
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
match def {
def::DefVariant(enum_id, variant_id, _) => {
let adt_def = cx.tcx.lookup_adt_def(enum_id);
if adt_def.variants.len() > 1 {
- PatternKind::Variant { adt_def: adt_def,
- variant_index: adt_def.variant_index_with_id(variant_id),
- subpatterns: subpatterns }
+ PatternKind::Variant {
+ adt_def: adt_def,
+ variant_index: adt_def.variant_index_with_id(variant_id),
+ subpatterns: subpatterns,
+ }
} else {
PatternKind::Leaf { subpatterns: subpatterns }
}
}
_ => {
- cx.tcx.sess.span_bug(
- self.pat.span,
- &format!("inappropriate def for pattern: {:?}", def));
+ cx.tcx.sess.span_bug(self.pat.span,
+ &format!("inappropriate def for pattern: {:?}", def));
}
}
}
}
-impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
- type Output = Pattern<Cx<'a,'tcx>>;
+impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
+ type Output = Pattern<'tcx>;
- fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Pattern<Cx<'a,'tcx>> {
+ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> {
let kind = match self.pat.node {
- hir::PatWild(..) =>
- PatternKind::Wild,
+ hir::PatWild(..) => PatternKind::Wild,
- hir::PatLit(ref lt) =>
- PatternKind::Constant { expr: lt.to_ref() },
+ hir::PatLit(ref value) => {
+ let value = const_eval::eval_const_expr(cx.tcx, value);
+ let value = Literal::Value { value: value };
+ PatternKind::Constant { value: value }
+ }
- hir::PatRange(ref begin, ref end) =>
- PatternKind::Range { lo: begin.to_ref(),
- hi: end.to_ref() },
+ hir::PatRange(ref lo, ref hi) => {
+ let lo = const_eval::eval_const_expr(cx.tcx, lo);
+ let lo = Literal::Value { value: lo };
+ let hi = const_eval::eval_const_expr(cx.tcx, hi);
+ let hi = Literal::Value { value: hi };
+ PatternKind::Range { lo: lo, hi: hi }
+ },
hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..)
if pat_is_resolved_const(&cx.tcx.def_map, self.pat) =>
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
match def {
def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
- match lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
- Some(const_expr) =>
- PatternKind::Constant { expr: const_expr.to_ref() },
- None =>
+ match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
+ Some(const_expr) => {
+ let opt_value =
+ const_eval::eval_const_expr_partial(
+ cx.tcx, const_expr,
+ const_eval::EvalHint::ExprTypeChecked,
+ None);
+ let literal = if let Ok(value) = opt_value {
+ Literal::Value { value: value }
+ } else {
+ let substs = cx.tcx.mk_substs(Substs::empty());
+ Literal::Item { def_id: def_id, substs: substs }
+ };
+ PatternKind::Constant { value: literal }
+ }
+ None => {
cx.tcx.sess.span_bug(
self.pat.span,
- &format!("cannot eval constant: {:?}", def_id)),
+ &format!("cannot eval constant: {:?}", def_id))
+ }
},
_ =>
cx.tcx.sess.span_bug(
{
let id = match self.binding_map {
None => self.pat.id,
- Some(ref map) => map[&ident.node],
+ Some(ref map) => map[&mtwt::resolve(ident.node)],
};
let var_ty = cx.tcx.node_id_to_type(self.pat.id);
let region = match var_ty.sty {
PatternKind::Binding {
mutability: mutability,
mode: mode,
- name: ident.node,
+ name: ident.node.name,
var: id,
ty: var_ty,
subpattern: self.opt_pat_ref(sub),
let subpatterns =
fields.iter()
.map(|field| FieldPatternRef {
- field: Field::Named(field.node.ident.name),
+ field: Field::Named(field.node.name),
pattern: self.pat_ref(&field.node.pat),
})
.collect();
}
hir::PatQPath(..) => {
- cx.tcx.sess.span_bug(
- self.pat.span,
- "unexpanded macro or bad constant etc");
+ cx.tcx.sess.span_bug(self.pat.span, "unexpanded macro or bad constant etc");
}
};
let ty = cx.tcx.node_id_to_type(self.pat.id);
- Pattern { span: self.pat.span,
- ty: ty,
- kind: kind }
+ Pattern {
+ span: self.pat.span,
+ ty: ty,
+ kind: kind,
+ }
}
}
use hair::*;
use repr::*;
-use tcx::Cx;
use tcx::pattern::PatNode;
-use tcx::rustc_front::hir;
-use tcx::syntax::ptr::P;
+use rustc_front::hir;
+use syntax::ptr::P;
-pub trait ToRef<H> {
+pub trait ToRef {
type Output;
fn to_ref(self) -> Self::Output;
}
-impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for &'tcx hir::Expr {
- type Output = ExprRef<Cx<'a,'tcx>>;
+impl<'a,'tcx:'a> ToRef for &'tcx hir::Expr {
+ type Output = ExprRef<'tcx>;
- fn to_ref(self) -> ExprRef<Cx<'a,'tcx>> {
+ fn to_ref(self) -> ExprRef<'tcx> {
ExprRef::Hair(self)
}
}
-impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for &'tcx P<hir::Expr> {
- type Output = ExprRef<Cx<'a,'tcx>>;
+impl<'a,'tcx:'a> ToRef for &'tcx P<hir::Expr> {
+ type Output = ExprRef<'tcx>;
- fn to_ref(self) -> ExprRef<Cx<'a,'tcx>> {
+ fn to_ref(self) -> ExprRef<'tcx> {
ExprRef::Hair(&**self)
}
}
-impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for Expr<Cx<'a,'tcx>> {
- type Output = ExprRef<Cx<'a,'tcx>>;
+impl<'a,'tcx:'a> ToRef for Expr<'tcx> {
+ type Output = ExprRef<'tcx>;
- fn to_ref(self) -> ExprRef<Cx<'a,'tcx>> {
+ fn to_ref(self) -> ExprRef<'tcx> {
ExprRef::Mirror(Box::new(self))
}
}
-impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for PatNode<'tcx> {
- type Output = PatternRef<Cx<'a,'tcx>>;
+impl<'a,'tcx:'a> ToRef for PatNode<'tcx> {
+ type Output = PatternRef<'tcx>;
- fn to_ref(self) -> PatternRef<Cx<'a,'tcx>> {
+ fn to_ref(self) -> PatternRef<'tcx> {
PatternRef::Hair(self)
}
}
-impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for Pattern<Cx<'a,'tcx>> {
- type Output = PatternRef<Cx<'a,'tcx>>;
+impl<'a,'tcx:'a> ToRef for Pattern<'tcx> {
+ type Output = PatternRef<'tcx>;
- fn to_ref(self) -> PatternRef<Cx<'a,'tcx>> {
+ fn to_ref(self) -> PatternRef<'tcx> {
PatternRef::Mirror(Box::new(self))
}
}
-impl<'a,'tcx:'a,T,U> ToRef<Cx<'a,'tcx>> for &'tcx Option<T>
- where &'tcx T: ToRef<Cx<'a,'tcx>, Output=U>
+impl<'a,'tcx:'a,T,U> ToRef for &'tcx Option<T>
+ where &'tcx T: ToRef<Output=U>
{
type Output = Option<U>;
}
}
-impl<'a,'tcx:'a,T,U> ToRef<Cx<'a,'tcx>> for &'tcx Vec<T>
- where &'tcx T: ToRef<Cx<'a,'tcx>, Output=U>
+impl<'a,'tcx:'a,T,U> ToRef for &'tcx Vec<T>
+ where &'tcx T: ToRef<Output=U>
{
type Output = Vec<U>;
}
}
-impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for &'tcx hir::Field {
- type Output = FieldExprRef<Cx<'a,'tcx>>;
+impl<'a,'tcx:'a> ToRef for &'tcx hir::Field {
+ type Output = FieldExprRef<'tcx>;
- fn to_ref(self) -> FieldExprRef<Cx<'a,'tcx>> {
+ fn to_ref(self) -> FieldExprRef<'tcx> {
FieldExprRef {
- name: Field::Named(self.ident.node.name),
- expr: self.expr.to_ref()
+ name: Field::Named(self.name.node),
+ expr: self.expr.to_ref(),
}
}
}
-
// The parent is considered the enclosing enum because the
// enum will dictate the privacy visibility of this variant
// instead.
- self.parents.insert(variant.node.id, item.id);
+ self.parents.insert(variant.node.data.id(), item.id);
}
}
visit::walk_impl_item(self, ii);
}
- fn visit_struct_def(&mut self, s: &hir::StructDef, _: ast::Ident,
- _: &'v hir::Generics, n: ast::NodeId) {
+ fn visit_variant_data(&mut self, s: &hir::VariantData, _: ast::Name,
+ _: &'v hir::Generics, item_id: ast::NodeId, _: Span) {
// Struct constructors are parented to their struct definitions because
// they essentially are the struct definitions.
- match s.ctor_id {
- Some(id) => { self.parents.insert(id, n); }
- None => {}
+ if !s.is_struct() {
+ self.parents.insert(s.id(), item_id);
}
// While we have the id of the struct definition, go ahead and parent
// all the fields.
- for field in &s.fields {
+ for field in s.fields() {
self.parents.insert(field.node.id, self.curparent);
}
visit::walk_struct_def(self, s)
// public all variants are public unless they're explicitly priv
hir::ItemEnum(ref def, _) if public_first => {
for variant in &def.variants {
- self.exported_items.insert(variant.node.id);
- self.public_items.insert(variant.node.id);
+ self.exported_items.insert(variant.node.data.id());
+ self.public_items.insert(variant.node.data.id());
}
}
hir::TyPath(..) => {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
def::DefPrimTy(..) => true,
+ def::DefSelfTy(..) => true,
def => {
let did = def.def_id();
- !did.is_local() ||
- self.exported_items.contains(&did.node)
+ if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+ self.exported_items.contains(&node_id)
+ } else {
+ true
+ }
}
}
}
_ => true,
};
- let tr = self.tcx.impl_trait_ref(DefId::local(item.id));
+ let tr = self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id));
let public_trait = tr.clone().map_or(false, |tr| {
- !tr.def_id.is_local() ||
- self.exported_items.contains(&tr.def_id.node)
+ if let Some(node_id) = self.tcx.map.as_local_node_id(tr.def_id) {
+ self.exported_items.contains(&node_id)
+ } else {
+ true
+ }
});
if public_ty || public_trait {
// Struct constructors are public if the struct is all public.
hir::ItemStruct(ref def, _) if public_first => {
- match def.ctor_id {
- Some(id) => { self.exported_items.insert(id); }
- None => {}
+ if !def.is_struct() {
+ self.exported_items.insert(def.id());
}
// fields can be public or private, so lets check
- for field in &def.fields {
+ for field in def.fields() {
let vis = match field.node.kind {
hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis
};
hir::ItemTy(ref ty, _) if public_first => {
if let hir::TyPath(..) = ty.node {
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
- def::DefPrimTy(..) | def::DefTyParam(..) => {},
+ def::DefPrimTy(..) | def::DefSelfTy(..) | def::DefTyParam(..) => {},
def => {
let did = def.def_id();
- if did.is_local() {
- self.exported_items.insert(did.node);
+ if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+ self.exported_items.insert(node_id);
}
}
}
if self.prev_exported {
assert!(self.export_map.contains_key(&id), "wut {}", id);
for export in self.export_map.get(&id).unwrap() {
- if export.def_id.is_local() {
- self.reexports.insert(export.def_id.node);
+ if let Some(node_id) = self.tcx.map.as_local_node_id(export.def_id) {
+ self.reexports.insert(node_id);
}
}
}
external_exports: ExternalExports,
}
+#[derive(Debug)]
enum PrivacyResult {
Allowable,
ExternallyDenied,
enum FieldName {
UnnamedField(usize), // index
- // (Name, not Ident, because struct fields are not macro-hygienic)
NamedField(ast::Name),
}
// Determines whether the given definition is public from the point of view
// of the current item.
fn def_privacy(&self, did: DefId) -> PrivacyResult {
- if !did.is_local() {
+ let node_id = if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+ node_id
+ } else {
if self.external_exports.contains(&did) {
debug!("privacy - {:?} was externally exported", did);
return Allowable;
ExternallyDenied
}
};
- }
+ };
debug!("privacy - local {} not public all the way down",
- self.tcx.map.node_to_string(did.node));
+ self.tcx.map.node_to_string(node_id));
// return quickly for things in the same module
- if self.parents.get(&did.node) == self.parents.get(&self.curitem) {
+ if self.parents.get(&node_id) == self.parents.get(&self.curitem) {
debug!("privacy - same parent, we're done here");
return Allowable;
}
// We now know that there is at least one private member between the
// destination and the root.
- let mut closest_private_id = did.node;
+ let mut closest_private_id = node_id;
loop {
debug!("privacy - examining {}", self.nodestr(closest_private_id));
let vis = match self.tcx.map.find(closest_private_id) {
}
}
+ /// True if `id` is both local and private-accessible
+ fn local_private_accessible(&self, did: DefId) -> bool {
+ if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+ self.private_accessible(node_id)
+ } else {
+ false
+ }
+ }
+
/// For a local private node in the AST, this function will determine
/// whether the node is accessible by the current module that iteration is
/// inside.
/// Guarantee that a particular definition is public. Returns a CheckResult
/// which contains any errors found. These can be reported using `report_error`.
/// If the result is `None`, no errors were found.
- fn ensure_public(&self, span: Span, to_check: DefId,
- source_did: Option<DefId>, msg: &str) -> CheckResult {
- let id = match self.def_privacy(to_check) {
+ fn ensure_public(&self,
+ span: Span,
+ to_check: DefId,
+ source_did: Option<DefId>,
+ msg: &str)
+ -> CheckResult {
+ debug!("ensure_public(span={:?}, to_check={:?}, source_did={:?}, msg={:?})",
+ span, to_check, source_did, msg);
+ let def_privacy = self.def_privacy(to_check);
+ debug!("ensure_public: def_privacy={:?}", def_privacy);
+ let id = match def_privacy {
ExternallyDenied => {
return Some((span, format!("{} is private", msg), None))
}
DisallowedBy(id) => id,
};
- // If we're disallowed by a particular id, then we attempt to give a
- // nice error message to say why it was disallowed. It was either
- // because the item itself is private or because its parent is private
- // and its parent isn't in our ancestry.
- let (err_span, err_msg) = if id == source_did.unwrap_or(to_check).node {
+ // If we're disallowed by a particular id, then we attempt to
+ // give a nice error message to say why it was disallowed. It
+ // was either because the item itself is private or because
+ // its parent is private and its parent isn't in our
+ // ancestry. (Both the item being checked and its parent must
+ // be local.)
+ let def_id = source_did.unwrap_or(to_check);
+ let node_id = self.tcx.map.as_local_node_id(def_id);
+ let (err_span, err_msg) = if Some(id) == node_id {
return Some((span, format!("{} is private", msg), None));
} else {
(span, format!("{} is inaccessible", msg))
};
let def = self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
let did = def.def_id();
- assert!(did.is_local());
- match self.tcx.map.get(did.node) {
+ let node_id = self.tcx.map.as_local_node_id(did).unwrap();
+ match self.tcx.map.get(node_id) {
ast_map::NodeItem(item) => item,
_ => self.tcx.sess.span_bug(item.span,
"path is not an item")
hir::ItemEnum(..) => "enum",
_ => return Some((err_span, err_msg, None))
};
- let msg = format!("{} `{}` is private", desc, item.ident);
+ let msg = format!("{} `{}` is private", desc, item.name);
Some((err_span, err_msg, Some((span, msg))))
}
}
UnnamedField(idx) => &v.fields[idx]
};
- if field.vis == hir::Public ||
- (field.did.is_local() && self.private_accessible(field.did.node)) {
- return
+ if field.vis == hir::Public || self.local_private_accessible(field.did) {
+ return;
}
let struct_desc = match def.adt_kind() {
span: Span,
method_id: DefId,
name: ast::Name) {
- // If the method is a default method, we need to use the def_id of
- // the default implementation.
- let method_id = match self.tcx.impl_or_trait_item(method_id) {
- ty::MethodTraitItem(method_type) => {
- method_type.provided_source.unwrap_or(method_id)
- }
- _ => {
- self.tcx.sess
- .span_bug(span,
- "got non-method item in check_static_method")
- }
- };
-
self.report_error(self.ensure_public(span,
method_id,
None,
impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
- if let hir::ItemUse(ref vpath) = item.node {
- if let hir::ViewPathList(ref prefix, ref list) = vpath.node {
- for pid in list {
- match pid.node {
- hir::PathListIdent { id, name, .. } => {
- debug!("privacy - ident item {}", id);
- self.check_path(pid.span, id, name.name);
- }
- hir::PathListMod { id, .. } => {
- debug!("privacy - mod item {}", id);
- let name = prefix.segments.last().unwrap().identifier.name;
- self.check_path(pid.span, id, name);
- }
- }
- }
- }
- }
let orig_curitem = replace(&mut self.curitem, item.id);
visit::walk_item(self, item);
self.curitem = orig_curitem;
fn visit_expr(&mut self, expr: &hir::Expr) {
match expr.node {
- hir::ExprField(ref base, ident) => {
+ hir::ExprField(ref base, name) => {
if let ty::TyStruct(def, _) = self.tcx.expr_ty_adjusted(&**base).sty {
self.check_field(expr.span,
def,
def.struct_variant(),
- NamedField(ident.node.name));
+ NamedField(name.node));
}
}
hir::ExprTupField(ref base, idx) => {
UnnamedField(idx.node));
}
}
- hir::ExprMethodCall(ident, _, _) => {
+ hir::ExprMethodCall(name, _, _) => {
let method_call = ty::MethodCall::expr(expr.id);
let method = self.tcx.tables.borrow().method_map[&method_call];
debug!("(privacy checking) checking impl method");
- self.check_method(expr.span, method.def_id, ident.node.name);
+ self.check_method(expr.span, method.def_id, name.node);
}
hir::ExprStruct(..) => {
let adt = self.tcx.expr_ty(expr).ty_adt_def().unwrap();
_ => expr_ty
}.ty_adt_def().unwrap();
let any_priv = def.struct_variant().fields.iter().any(|f| {
- f.vis != hir::Public && (
- !f.did.is_local() ||
- !self.private_accessible(f.did.node))
- });
-
+ f.vis != hir::Public && !self.local_private_accessible(f.did)
+ });
if any_priv {
span_err!(self.tcx.sess, expr.span, E0450,
"cannot invoke tuple struct constructor with private \
let variant = adt.variant_of_def(def);
for field in fields {
self.check_field(pattern.span, adt, variant,
- NamedField(field.node.ident.name));
+ NamedField(field.node.name));
}
}
}
fn visit_path(&mut self, path: &hir::Path, id: ast::NodeId) {
- self.check_path(path.span, id, path.segments.last().unwrap().identifier.name);
- visit::walk_path(self, path);
+ if !path.segments.is_empty() {
+ self.check_path(path.span, id, path.segments.last().unwrap().identifier.name);
+ visit::walk_path(self, path);
+ }
+ }
+
+ fn visit_path_list_item(&mut self, prefix: &hir::Path, item: &hir::PathListItem) {
+ let name = if let hir::PathListIdent { name, .. } = item.node {
+ name
+ } else if !prefix.segments.is_empty() {
+ prefix.segments.last().unwrap().identifier.name
+ } else {
+ self.tcx.sess.bug("`self` import in an import list with empty prefix");
+ };
+ self.check_path(item.span, item.node.id(), name);
+ visit::walk_path_list_item(self, prefix, item);
}
}
instead");
}
- hir::ItemEnum(ref def, _) => {
- for v in &def.variants {
- match v.node.vis {
- hir::Public => {
- if item.vis == hir::Public {
- span_err!(tcx.sess, v.span, E0448,
- "unnecessary `pub` visibility");
- }
- }
- hir::Inherited => {}
- }
- }
- }
-
+ hir::ItemEnum(..) |
hir::ItemTrait(..) | hir::ItemDefaultImpl(..) |
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemStruct(..) |
hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemTy(..) |
"visibility has no effect inside functions");
}
}
- let check_struct = |def: &hir::StructDef| {
- for f in &def.fields {
+ let check_struct = |def: &hir::VariantData| {
+ for f in def.fields() {
match f.node.kind {
hir::NamedField(_, p) => check_inherited(tcx, f.span, p),
hir::UnnamedField(..) => {}
check_inherited(tcx, i.span, i.vis);
}
}
- hir::ItemEnum(ref def, _) => {
- for v in &def.variants {
- check_inherited(tcx, v.span, v.node.vis);
- }
- }
- hir::ItemStruct(ref def, _) => check_struct(&**def),
+ hir::ItemStruct(ref def, _) => check_struct(def),
+ hir::ItemEnum(..) |
hir::ItemExternCrate(_) | hir::ItemUse(_) |
hir::ItemTrait(..) | hir::ItemDefaultImpl(..) |
hir::ItemStatic(..) | hir::ItemConst(..) |
fn path_is_private_type(&self, path_id: ast::NodeId) -> bool {
let did = match self.tcx.def_map.borrow().get(&path_id).map(|d| d.full_def()) {
// `int` etc. (None doesn't seem to occur.)
- None | Some(def::DefPrimTy(..)) => return false,
+ None | Some(def::DefPrimTy(..)) | Some(def::DefSelfTy(..)) => return false,
Some(def) => def.def_id(),
};
+
// A path can only be private if:
// it's in this crate...
- if !did.is_local() {
+ if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+ // .. and it corresponds to a private type in the AST (this returns
+ // None for type parameters)
+ match self.tcx.map.find(node_id) {
+ Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public,
+ Some(_) | None => false,
+ }
+ } else {
return false
}
-
- // .. and it corresponds to a private type in the AST (this returns
- // None for type parameters)
- match self.tcx.map.find(did.node) {
- Some(ast_map::NodeItem(ref item)) => item.vis != hir::Public,
- Some(_) | None => false,
- }
}
fn trait_is_public(&self, trait_id: ast::NodeId) -> bool {
|tr| {
let did = self.tcx.trait_ref_to_def_id(tr);
- !did.is_local() || self.trait_is_public(did.node)
+ if let Some(node_id) = self.tcx.map.as_local_node_id(did) {
+ self.trait_is_public(node_id)
+ } else {
+ true // external traits must be public
+ }
});
// `true` iff this is a trait impl or at least one method is public.
visit::walk_ty(self, t)
}
- fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics) {
- if self.exported_items.contains(&v.node.id) {
+ fn visit_variant(&mut self, v: &hir::Variant, g: &hir::Generics, item_id: ast::NodeId) {
+ if self.exported_items.contains(&v.node.data.id()) {
self.in_variant = true;
- visit::walk_variant(self, v, g);
+ visit::walk_variant(self, v, g, item_id);
self.in_variant = false;
}
}
fn visit_struct_field(&mut self, s: &hir::StructField) {
- match s.node.kind {
- hir::NamedField(_, vis) if vis == hir::Public || self.in_variant => {
- visit::walk_struct_field(self, s);
- }
- _ => {}
+ let vis = match s.node.kind {
+ hir::NamedField(_, vis) | hir::UnnamedField(vis) => vis
+ };
+ if vis == hir::Public || self.in_variant {
+ visit::walk_struct_field(self, s);
}
}
use rustc::metadata::csearch;
use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
use rustc::middle::def::*;
-use rustc::middle::def_id::DefId;
+use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
use syntax::ast::{Name, NodeId};
+use syntax::attr::AttrMetaMethods;
use syntax::parse::token::special_idents;
use syntax::codemap::{Span, DUMMY_SP};
use rustc_front::hir::{ItemStruct, ItemTrait, ItemTy, ItemUse};
use rustc_front::hir::{NamedField, PathListIdent, PathListMod, Public};
use rustc_front::hir::StmtDecl;
-use rustc_front::hir::StructVariantKind;
-use rustc_front::hir::TupleVariantKind;
use rustc_front::hir::UnnamedField;
use rustc_front::hir::{Variant, ViewPathGlob, ViewPathList, ViewPathSimple};
use rustc_front::hir::Visibility;
-use rustc_front::attr::AttrMetaMethods;
use rustc_front::visit::{self, Visitor};
use std::mem::replace;
/// Constructs the reduced graph for one item.
fn build_reduced_graph_for_item(&mut self, item: &Item, parent: &Rc<Module>) -> Rc<Module> {
- let name = item.ident.name;
+ let name = item.name;
let sp = item.span;
let is_public = item.vis == hir::Public;
let modifiers = if is_public {
ViewPathSimple(_, ref full_path) => {
full_path.segments
.split_last().unwrap().1
- .iter().map(|ident| ident.identifier.name)
+ .iter().map(|seg| seg.identifier.name)
.collect()
}
ViewPathGlob(ref module_ident_path) |
ViewPathList(ref module_ident_path, _) => {
module_ident_path.segments
- .iter().map(|ident| ident.identifier.name).collect()
+ .iter().map(|seg| seg.identifier.name).collect()
}
};
ResolutionError::SelfImportsOnlyAllowedWithin);
}
- let subclass = SingleImport(binding.name,
- source_name);
+ let subclass = SingleImport(binding, source_name);
self.build_import_directive(&**parent,
module_path,
subclass,
for source_item in source_items {
let (module_path, name, rename) = match source_item.node {
PathListIdent { name, rename, .. } =>
- (module_path.clone(), name.name, rename.unwrap_or(name).name),
+ (module_path.clone(), name, rename.unwrap_or(name)),
PathListMod { rename, .. } => {
let name = match module_path.last() {
Some(name) => *name,
}
};
let module_path = module_path.split_last().unwrap().1;
- let rename = rename.map(|n| n.name).unwrap_or(name);
+ let rename = rename.unwrap_or(name);
(module_path.to_vec(), name, rename)
}
};
ItemExternCrate(_) => {
// n.b. we don't need to look at the path option here, because cstore already did
if let Some(crate_id) = self.session.cstore.find_extern_mod_stmt_cnum(item.id) {
- let def_id = DefId { krate: crate_id, node: 0 };
+ let def_id = DefId { krate: crate_id, index: CRATE_DEF_INDEX };
self.external_exports.insert(def_id);
let parent_link = ModuleParentLink(Rc::downgrade(parent), name);
let external_module = Rc::new(Module::new(parent_link,
}
ItemMod(..) => {
+ let child = parent.children.borrow().get(&name).cloned();
+ if let Some(child) = child {
+ // check if there's struct of the same name already defined
+ if child.defined_in_namespace(TypeNS)
+ && child.get_module_if_available().is_none() {
+ self.session.span_warn(sp, &format!(
+ "duplicate definition of {} `{}`. \
+ Defining a module and a struct with \
+ the same name will be disallowed \
+ soon.",
+ namespace_error_to_string(TypeError),
+ name));
+ {
+ let r = child.span_for_namespace(TypeNS);
+ if let Some(sp) = r {
+ self.session.span_note(sp,
+ &format!("first definition of {} `{}` here",
+ namespace_error_to_string(TypeError),
+ name));
+ }
+ }
+ }
+ }
let name_bindings = self.add_child(name, parent, ForbidDuplicateModules, sp);
let parent_link = self.get_parent_link(parent, name);
- let def_id = DefId { krate: 0, node: item.id };
+ let def_id = self.ast_map.local_def_id(item.id);
name_bindings.define_module(parent_link,
Some(def_id),
NormalModuleKind,
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
let mutbl = m == hir::MutMutable;
- name_bindings.define_value(DefStatic(DefId::local(item.id), mutbl), sp, modifiers);
+ name_bindings.define_value(DefStatic(self.ast_map.local_def_id(item.id), mutbl),
+ sp,
+ modifiers);
parent.clone()
}
ItemConst(_, _) => {
self.add_child(name, parent, ForbidDuplicateValues, sp)
- .define_value(DefConst(DefId::local(item.id)), sp, modifiers);
+ .define_value(DefConst(self.ast_map.local_def_id(item.id)), sp, modifiers);
parent.clone()
}
ItemFn(_, _, _, _, _, _) => {
let name_bindings = self.add_child(name, parent, ForbidDuplicateValues, sp);
- let def = DefFn(DefId::local(item.id), false);
+ let def = DefFn(self.ast_map.local_def_id(item.id), false);
name_bindings.define_value(def, sp, modifiers);
parent.clone()
}
let name_bindings =
self.add_child(name, parent, ForbidDuplicateTypesAndModules, sp);
- name_bindings.define_type(DefTy(DefId::local(item.id), false), sp,
+ name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false), sp,
modifiers);
let parent_link = self.get_parent_link(parent, name);
name_bindings.set_module_kind(parent_link,
- Some(DefId::local(item.id)),
+ Some(self.ast_map.local_def_id(item.id)),
TypeModuleKind,
false,
is_public,
let name_bindings =
self.add_child(name, parent, ForbidDuplicateTypesAndModules, sp);
- name_bindings.define_type(DefTy(DefId::local(item.id), true), sp, modifiers);
+ name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), true),
+ sp,
+ modifiers);
let parent_link = self.get_parent_link(parent, name);
name_bindings.set_module_kind(parent_link,
- Some(DefId::local(item.id)),
+ Some(self.ast_map.local_def_id(item.id)),
EnumModuleKind,
false,
is_public,
let module = name_bindings.get_module();
for variant in &(*enum_definition).variants {
+ let item_def_id = self.ast_map.local_def_id(item.id);
self.build_reduced_graph_for_variant(
&**variant,
- DefId::local(item.id),
+ item_def_id,
&module);
}
parent.clone()
// These items live in both the type and value namespaces.
ItemStruct(ref struct_def, _) => {
// Adding to both Type and Value namespaces or just Type?
- let (forbid, ctor_id) = match struct_def.ctor_id {
- Some(ctor_id) => (ForbidDuplicateTypesAndValues, Some(ctor_id)),
- None => (ForbidDuplicateTypesAndModules, None)
+ let (forbid, ctor_id) = if struct_def.is_struct() {
+ (ForbidDuplicateTypesAndModules, None)
+ } else {
+ let child = parent.children.borrow().get(&name).cloned();
+ if let Some(child) = child {
+ // check if theres a DefMod
+ if let Some(DefMod(_)) = child.def_for_namespace(TypeNS) {
+ self.session.span_warn(sp, &format!(
+ "duplicate definition of {} `{}`. \
+ Defining a module and a struct with \
+ the same name will be disallowed \
+ soon.",
+ namespace_error_to_string(TypeError),
+ name));
+ {
+ let r = child.span_for_namespace(TypeNS);
+ if let Some(sp) = r {
+ self.session.span_note(sp,
+ &format!("first definition of {} `{}` here",
+ namespace_error_to_string(TypeError),
+ name));
+ }
+ }
+ }
+ }
+ (ForbidDuplicateTypesAndValues, Some(struct_def.id()))
};
let name_bindings = self.add_child(name, parent, forbid, sp);
// Define a name in the type namespace.
- name_bindings.define_type(DefTy(DefId::local(item.id), false), sp, modifiers);
+ name_bindings.define_type(DefTy(self.ast_map.local_def_id(item.id), false),
+ sp,
+ modifiers);
// If this is a newtype or unit-like struct, define a name
// in the value namespace as well
if let Some(cid) = ctor_id {
- name_bindings.define_value(DefStruct(DefId::local(cid)), sp, modifiers);
+ name_bindings.define_value(DefStruct(self.ast_map.local_def_id(cid)),
+ sp,
+ modifiers);
}
// Record the def ID and fields of this struct.
- let named_fields = struct_def.fields.iter().filter_map(|f| {
+ let named_fields = struct_def.fields().iter().filter_map(|f| {
match f.node.kind {
- NamedField(ident, _) => Some(ident.name),
+ NamedField(name, _) => Some(name),
UnnamedField(_) => None
}
}).collect();
- self.structs.insert(DefId::local(item.id), named_fields);
+ let item_def_id = self.ast_map.local_def_id(item.id);
+ self.structs.insert(item_def_id, named_fields);
parent.clone()
}
// Add all the items within to a new module.
let parent_link = self.get_parent_link(parent, name);
name_bindings.define_module(parent_link,
- Some(DefId::local(item.id)),
+ Some(self.ast_map.local_def_id(item.id)),
TraitModuleKind,
false,
is_public,
sp);
let module_parent = name_bindings.get_module();
- let def_id = DefId::local(item.id);
+ let def_id = self.ast_map.local_def_id(item.id);
// Add the names of all the items to the trait info.
for trait_item in items {
- let name_bindings = self.add_child(trait_item.ident.name,
+ let name_bindings = self.add_child(trait_item.name,
&module_parent,
ForbidDuplicateTypesAndValues,
trait_item.span);
match trait_item.node {
hir::ConstTraitItem(..) => {
- let def = DefAssociatedConst(DefId::local(trait_item.id));
+ let def = DefAssociatedConst(self.ast_map.local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
}
hir::MethodTraitItem(..) => {
- let def = DefMethod(DefId::local(trait_item.id));
+ let def = DefMethod(self.ast_map.local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_value(def, trait_item.span, DefModifiers::PUBLIC);
}
hir::TypeTraitItem(..) => {
- let def = DefAssociatedTy(DefId::local(item.id),
- DefId::local(trait_item.id));
+ let def = DefAssociatedTy(self.ast_map.local_def_id(item.id),
+ self.ast_map.local_def_id(trait_item.id));
// NB: not DefModifiers::IMPORTABLE
name_bindings.define_type(def, trait_item.span, DefModifiers::PUBLIC);
}
}
- self.trait_item_map.insert((trait_item.ident.name, def_id),
- DefId::local(trait_item.id));
+ let trait_item_def_id = self.ast_map.local_def_id(trait_item.id);
+ self.trait_item_map.insert((trait_item.name, def_id), trait_item_def_id);
}
name_bindings.define_type(DefTrait(def_id), sp, modifiers);
variant: &Variant,
item_id: DefId,
parent: &Rc<Module>) {
- let name = variant.node.name.name;
- let is_exported = match variant.node.kind {
- TupleVariantKind(_) => false,
- StructVariantKind(_) => {
- // Not adding fields for variants as they are not accessed with a self receiver
- self.structs.insert(DefId::local(variant.node.id), Vec::new());
- true
- }
+ let name = variant.node.name;
+ let is_exported = if variant.node.data.is_struct() {
+ // Not adding fields for variants as they are not accessed with a self receiver
+ let variant_def_id = self.ast_map.local_def_id(variant.node.data.id());
+ self.structs.insert(variant_def_id, Vec::new());
+ true
+ } else {
+ false
};
let child = self.add_child(name, parent,
// variants are always treated as importable to allow them to be glob
// used
child.define_value(DefVariant(item_id,
- DefId::local(variant.node.id), is_exported),
+ self.ast_map.local_def_id(variant.node.data.id()),
+ is_exported),
variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
child.define_type(DefVariant(item_id,
- DefId::local(variant.node.id), is_exported),
+ self.ast_map.local_def_id(variant.node.data.id()),
+ is_exported),
variant.span, DefModifiers::PUBLIC | DefModifiers::IMPORTABLE);
}
fn build_reduced_graph_for_foreign_item(&mut self,
foreign_item: &ForeignItem,
parent: &Rc<Module>) {
- let name = foreign_item.ident.name;
+ let name = foreign_item.name;
let is_public = foreign_item.vis == hir::Public;
let modifiers = if is_public {
DefModifiers::PUBLIC
let def = match foreign_item.node {
ForeignItemFn(..) => {
- DefFn(DefId::local(foreign_item.id), false)
+ DefFn(self.ast_map.local_def_id(foreign_item.id), false)
}
ForeignItemStatic(_, m) => {
- DefStatic(DefId::local(foreign_item.id), m)
+ DefStatic(self.ast_map.local_def_id(foreign_item.id), m)
}
};
name_bindings.define_value(def, foreign_item.span, modifiers);
self.structs.insert(def_id, fields);
}
DefLocal(..) | DefPrimTy(..) | DefTyParam(..) |
- DefUse(..) | DefUpvar(..) | DefRegion(..) |
+ DefUse(..) | DefUpvar(..) |
DefLabel(..) | DefSelfTy(..) => {
panic!("didn't expect `{:?}`", def);
}
```
"##,
+E0422: r##"
+You are trying to use an identifier that is either undefined or not a
+struct. For instance:
+```
+fn main () {
+ let x = Foo { x: 1, y: 2 };
+}
+```
+
+In this case, `Foo` is undefined, so it inherently isn't anything, and
+definitely not a struct.
+
+```
+fn main () {
+ let foo = 1;
+ let x = foo { x: 1, y: 2 };
+}
+```
+
+In this case, `foo` is defined, but is not a struct, so Rust can't use
+it as one.
+"##,
+
E0423: r##"
A `struct` variant name was used like a function name. Example of
erroneous code:
E0418, // is not an enum variant, struct or const
E0420, // is not an associated const
E0421, // unresolved associated const
- E0422, // does not name a structure
E0427, // cannot use `ref` binding mode with ...
E0429, // `self` imports are only allowed within a { } list
E0434, // can't capture dynamic environment in a fn item
#![feature(borrow_state)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(slice_splits)]
#![feature(staged_api)]
#[macro_use] extern crate log;
use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl};
use rustc::middle::def::*;
use rustc::middle::def_id::DefId;
-use rustc::middle::pat_util::pat_bindings;
+use rustc::middle::pat_util::pat_bindings_hygienic;
use rustc::middle::privacy::*;
use rustc::middle::subst::{ParamSpace, FnSpace, TypeSpace};
use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap};
use rustc::util::lev_distance::lev_distance;
use syntax::ast;
-use syntax::ast::{Ident, Name, NodeId, CrateNum};
+use syntax::ast::{CRATE_NODE_ID, Ident, Name, NodeId, CrateNum, TyIs, TyI8, TyI16, TyI32, TyI64};
+use syntax::ast::{TyUs, TyU8, TyU16, TyU32, TyU64, TyF64, TyF32};
use syntax::attr::AttrMetaMethods;
use syntax::ext::mtwt;
use syntax::parse::token::{self, special_names, special_idents};
use rustc_front::hir::{Local, MethodImplItem};
use rustc_front::hir::{Pat, PatEnum, PatIdent, PatLit, PatQPath};
use rustc_front::hir::{PatRange, PatStruct, Path, PrimTy};
-use rustc_front::hir::{TraitRef, Ty, TyBool, TyChar, TyF32};
-use rustc_front::hir::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt};
-use rustc_front::hir::{TyPath, TyPtr};
-use rustc_front::hir::{TyRptr, TyStr, TyUs, TyU8, TyU16, TyU32, TyU64, TyUint};
+use rustc_front::hir::{TraitRef, Ty, TyBool, TyChar, TyFloat, TyInt};
+use rustc_front::hir::{TyRptr, TyStr, TyUint, TyPath, TyPtr};
use rustc_front::hir::TypeImplItem;
use rustc_front::util::walk_pat;
}
visit::walk_poly_trait_ref(self, tref, m);
}
- fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics) {
+ fn visit_variant(&mut self, variant: &hir::Variant, generics: &Generics, item_id: ast::NodeId) {
execute_callback!(hir_map::Node::NodeVariant(variant), self);
if let Some(ref dis_expr) = variant.node.disr_expr {
// resolve the discriminator expr as a constant
}
// `visit::walk_variant` without the discriminant expression.
- match variant.node.kind {
- hir::TupleVariantKind(ref variant_arguments) => {
- for variant_argument in variant_arguments {
- self.visit_ty(&*variant_argument.ty);
- }
- }
- hir::StructVariantKind(ref struct_definition) => {
- self.visit_struct_def(&**struct_definition,
- variant.node.name,
- generics,
- variant.node.id);
- }
- }
+ self.visit_variant_data(&variant.node.data, variant.node.name,
+ generics, item_id, variant.span);
}
fn visit_foreign_item(&mut self, foreign_item: &hir::ForeignItem) {
execute_callback!(hir_map::Node::NodeForeignItem(foreign_item), self);
make_glob_map: MakeGlobMap) -> Resolver<'a, 'tcx> {
let graph_root = NameBindings::new();
+ let root_def_id = ast_map.local_def_id(CRATE_NODE_ID);
graph_root.define_module(NoParentLink,
- Some(DefId { krate: 0, node: 0 }),
+ Some(root_def_id),
NormalModuleKind,
false,
true,
}
fn get_trait_name(&self, did: DefId) -> Name {
- if did.is_local() {
- self.ast_map.expect_item(did.node).ident.name
+ if let Some(node_id) = self.ast_map.as_local_node_id(did) {
+ self.ast_map.expect_item(node_id).name
} else {
csearch::get_trait_name(&self.session.cstore, did)
}
self.session.span_bug(span,
&format!("unexpected {:?} in bindings", def))
}
- DefLocal(node_id) => {
+ DefLocal(_, node_id) => {
for rib in ribs {
match rib.kind {
NormalRibKind => {
}
ClosureRibKind(function_id) => {
let prev_def = def;
+ let node_def_id = self.ast_map.local_def_id(node_id);
let mut seen = self.freevars_seen.borrow_mut();
let seen = seen.entry(function_id).or_insert_with(|| NodeMap());
if let Some(&index) = seen.get(&node_id) {
- def = DefUpvar(node_id, index, function_id);
+ def = DefUpvar(node_def_id, node_id, index, function_id);
continue;
}
let mut freevars = self.freevars.borrow_mut();
let depth = vec.len();
vec.push(Freevar { def: prev_def, span: span });
- def = DefUpvar(node_id, depth, function_id);
+ def = DefUpvar(node_def_id, node_id, depth, function_id);
seen.insert(node_id, depth);
}
ItemRibKind | MethodRibKind => {
}
fn resolve_item(&mut self, item: &Item) {
- let name = item.ident.name;
+ let name = item.name;
debug!("(resolving item) resolving {}",
name);
TypeSpace,
ItemRibKind),
|this| {
- this.with_self_rib(DefSelfTy(Some(DefId::local(item.id)), None), |this| {
+ let local_def_id = this.ast_map.local_def_id(item.id);
+ this.with_self_rib(DefSelfTy(Some(local_def_id), None), |this| {
this.visit_generics(generics);
- visit::walk_ty_param_bounds_helper(this, bounds);
+ walk_list!(this, visit_ty_param_bound, bounds);
for trait_item in trait_items {
match trait_item.node {
});
}
hir::TypeTraitItem(..) => {
- this.check_if_primitive_type_name(trait_item.ident.name,
+ this.check_if_primitive_type_name(trait_item.name,
trait_item.span);
this.with_type_parameter_rib(NoTypeParameters, |this| {
visit::walk_trait_item(this, trait_item)
ItemUse(ref view_path) => {
// check for imports shadowing primitive types
- let check_rename = |id, ident: Ident| {
- match self.def_map.borrow().get(&id).map(|d| d.full_def()) {
+ let check_rename = |this: &Self, id, name| {
+ match this.def_map.borrow().get(&id).map(|d| d.full_def()) {
Some(DefTy(..)) | Some(DefStruct(..)) | Some(DefTrait(..)) | None => {
- self.check_if_primitive_type_name(ident.name, item.span);
+ this.check_if_primitive_type_name(name, item.span);
}
_ => {}
}
};
match view_path.node {
- hir::ViewPathSimple(ident, _) => {
- check_rename(item.id, ident);
+ hir::ViewPathSimple(name, _) => {
+ check_rename(self, item.id, name);
}
- hir::ViewPathList(_, ref items) => {
+ hir::ViewPathList(ref prefix, ref items) => {
for item in items {
- if let Some(ident) = item.node.rename() {
- check_rename(item.node.id(), ident);
+ if let Some(name) = item.node.rename() {
+ check_rename(self, item.node.id(), name);
+ }
+ }
+
+ // Resolve prefix of an import with empty braces (issue #28388)
+ if items.is_empty() && !prefix.segments.is_empty() {
+ match self.resolve_crate_relative_path(prefix.span,
+ &prefix.segments,
+ TypeNS) {
+ Some((def, lp)) => self.record_def(item.id,
+ PathResolution::new(def, lp, 0)),
+ None => {
+ resolve_error(self,
+ prefix.span,
+ ResolutionError::FailedToResolve(
+ &path_names_to_string(prefix, 0)));
+ }
}
}
}
let mut function_type_rib = Rib::new(rib_kind);
let mut seen_bindings = HashSet::new();
for (index, type_parameter) in generics.ty_params.iter().enumerate() {
- let name = type_parameter.ident.name;
+ let name = type_parameter.name;
debug!("with_type_parameter_rib: {}", type_parameter.id);
if seen_bindings.contains(&name) {
function_type_rib.bindings.insert(name,
DlDef(DefTyParam(space,
index as u32,
- DefId::local(type_parameter.id),
+ self.ast_map.local_def_id(type_parameter.id),
name)));
}
self.type_ribs.push(function_type_rib);
fn resolve_generics(&mut self, generics: &Generics) {
for type_parameter in generics.ty_params.iter() {
- self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span);
+ self.check_if_primitive_type_name(type_parameter.name, type_parameter.span);
}
for predicate in &generics.where_clause.predicates {
match predicate {
ConstImplItem(..) => {
// If this is a trait impl, ensure the const
// exists in trait
- this.check_trait_item(impl_item.ident.name,
+ this.check_trait_item(impl_item.name,
impl_item.span,
|n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
this.with_constant_rib(|this| {
MethodImplItem(ref sig, _) => {
// If this is a trait impl, ensure the method
// exists in trait
- this.check_trait_item(impl_item.ident.name,
+ this.check_trait_item(impl_item.name,
impl_item.span,
|n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
TypeImplItem(ref ty) => {
// If this is a trait impl, ensure the type
// exists in trait
- this.check_trait_item(impl_item.ident.name,
+ this.check_trait_item(impl_item.name,
impl_item.span,
|n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
fn resolve_local(&mut self, local: &Local) {
// Resolve the type.
- visit::walk_ty_opt(self, &local.ty);
+ walk_list!(self, visit_ty, &local.ty);
// Resolve the initializer.
- visit::walk_expr_opt(self, &local.init);
+ walk_list!(self, visit_expr, &local.init);
// Resolve the pattern.
self.resolve_pattern(&*local.pat,
// user and one 'x' came from the macro.
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
let mut result = HashMap::new();
- pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path1| {
+ pat_bindings_hygienic(&self.def_map, pat, |binding_mode, _id, sp, path1| {
let name = mtwt::resolve(path1.node);
result.insert(name, BindingInfo {
span: sp,
// pat_idents are variants
self.check_consistent_bindings(arm);
- visit::walk_expr_opt(self, &arm.guard);
+ walk_list!(self, visit_expr, &arm.guard);
self.visit_expr(&*arm.body);
if !self.resolved {
debug!("(resolving pattern) binding `{}`",
renamed);
- let def = DefLocal(pattern.id);
+ let def_id = self.ast_map.local_def_id(pattern.id);
+ let def = DefLocal(def_id, pattern.id);
// Record the definition so that later passes
// will be able to distinguish variants from
}
fn is_static_method(this: &Resolver, did: DefId) -> bool {
- if did.is_local() {
- let sig = match this.ast_map.get(did.node) {
+ if let Some(node_id) = this.ast_map.as_local_node_id(did) {
+ let sig = match this.ast_map.get(node_id) {
hir_map::NodeTraitItem(trait_item) => match trait_item.node {
hir::MethodTraitItem(ref sig, _) => sig,
_ => return false
false // Stop advancing
});
- if method_scope && special_names::self_ == path_name {
+ if method_scope && special_names::self_.as_str() == &path_name[..] {
resolve_error(
self,
expr.span,
fn record_candidate_traits_for_expr_if_necessary(&mut self, expr: &Expr) {
match expr.node {
- ExprField(_, ident) => {
+ ExprField(_, name) => {
// FIXME(#6890): Even though you can't treat a method like a
// field, we need to add any trait methods we find that match
// the field name so that we can do some nice error reporting
// later on in typeck.
- let traits = self.get_traits_containing_item(ident.node.name);
+ let traits = self.get_traits_containing_item(name.node);
self.trait_map.insert(expr.id, traits);
}
- ExprMethodCall(ident, _, _) => {
+ ExprMethodCall(name, _, _) => {
debug!("(recording candidate traits for expr) recording \
traits for {}",
expr.id);
- let traits = self.get_traits_containing_item(ident.node.name);
+ let traits = self.get_traits_containing_item(name.node);
self.trait_map.insert(expr.id, traits);
}
_ => {
fn add_trait_info(found_traits: &mut Vec<DefId>,
trait_def_id: DefId,
name: Name) {
- debug!("(adding trait info) found trait {}:{} for method '{}'",
- trait_def_id.krate,
- trait_def_id.node,
+ debug!("(adding trait info) found trait {:?} for method '{}'",
+ trait_def_id,
name);
found_traits.push(trait_def_id);
}
self.add_exports_for_module(&mut exports, module_);
match module_.def_id.get() {
Some(def_id) => {
- self.export_map.insert(def_id.node, exports);
- debug!("(computing exports) writing exports for {} (some)",
- def_id.node);
+ let node_id = self.ast_map.as_local_node_id(def_id).unwrap();
+ self.export_map.insert(node_id, exports);
+ debug!("(computing exports) writing exports for {} (some)", node_id);
}
None => {}
}
fn get_binding(this: &mut Resolver,
import_resolution: &ImportResolution,
namespace: Namespace,
- source: &Name)
+ source: Name)
-> NamespaceResult {
// Import resolutions must be declared with "pub"
let id = import_resolution.id(namespace);
// track used imports and extern crates as well
this.used_imports.insert((id, namespace));
- this.record_import_use(id, *source);
+ this.record_import_use(id, source);
match target_module.def_id.get() {
Some(DefId{krate: kid, ..}) => {
this.used_crates.insert(kid);
value_result = get_binding(self.resolver,
import_resolution,
ValueNS,
- &source);
+ source);
value_used_reexport = import_resolution.is_public;
}
if type_result.is_unknown() {
type_result = get_binding(self.resolver,
import_resolution,
TypeNS,
- &source);
+ source);
type_used_reexport = import_resolution.is_public;
}
)));
}
- for (ident, target_import_resolution) in import_resolutions.iter() {
+ for (name, target_import_resolution) in import_resolutions.iter() {
debug!("(resolving glob import) writing module resolution \
{} into `{}`",
- *ident,
+ *name,
module_to_string(module_));
if !target_import_resolution.is_public {
// Here we merge two import resolutions.
let mut import_resolutions = module_.import_resolutions.borrow_mut();
- match import_resolutions.get_mut(ident) {
+ match import_resolutions.get_mut(name) {
Some(dest_import_resolution) => {
// Merge the two import resolutions at a finer-grained
// level.
Some(ref value_target) => {
self.check_for_conflicting_import(&dest_import_resolution,
import_directive.span,
- *ident,
+ *name,
ValueNS);
dest_import_resolution.value_target = Some(value_target.clone());
}
Some(ref type_target) => {
self.check_for_conflicting_import(&dest_import_resolution,
import_directive.span,
- *ident,
+ *name,
TypeNS);
dest_import_resolution.type_target = Some(type_target.clone());
}
new_import_resolution.type_target =
target_import_resolution.type_target.clone();
- import_resolutions.insert(*ident, new_import_resolution);
+ import_resolutions.insert(*name, new_import_resolution);
}
// Add all children from the containing module.
/// Adds all of the contents of a native library to this archive. This will
/// search in the relevant locations for a library named `name`.
- pub fn add_native_library(&mut self, name: &str) -> io::Result<()> {
+ pub fn add_native_library(&mut self, name: &str) {
let location = find_library(name, &self.config.lib_search_paths,
self.config.sess);
- self.add_archive(&location, name, |_| false)
+ self.add_archive(&location, name, |_| false).unwrap_or_else(|e| {
+ self.config.sess.fatal(&format!("failed to add native library {}: {}",
+ location.to_string_lossy(), e));
+ });
}
/// Adds all of the contents of the rlib at the specified path to this
use super::svh::Svh;
use session::config;
use session::config::NoDebugInfo;
-use session::config::{OutputFilenames, Input, OutputTypeBitcode, OutputTypeExe, OutputTypeObject};
+use session::config::{OutputFilenames, Input, OutputType};
use session::search_paths::PathKind;
use session::Session;
use metadata::common::LinkMeta;
use metadata::{encoder, cstore, filesearch, csearch, creader};
use middle::dependency_format::Linkage;
use middle::ty::{self, Ty};
-use rustc::front::map::{PathElem, PathElems, PathName};
+use rustc::front::map::DefPath;
use trans::{CrateContext, CrateTranslation, gensym_name};
use util::common::time;
use util::sha2::{Digest, Sha256};
use util::fs::fix_windows_verbatim_for_gcc;
use rustc_back::tempdir::TempDir;
+use std::ascii;
+use std::char;
use std::env;
use std::ffi::OsString;
-use std::fs::{self, PathExt};
+use std::fs;
use std::io::{self, Read, Write};
+use std::iter::once;
use std::mem;
use std::path::{Path, PathBuf};
use std::process::Command;
use serialize::hex::ToHex;
use syntax::ast;
use syntax::codemap::Span;
-use syntax::parse::token;
+use syntax::parse::token::{self, InternedString};
use syntax::attr::AttrMetaMethods;
-use rustc_front::attr::AttrMetaMethods as FrontAttrMetaMethods;
use rustc_front::hir;
}
pub fn build_link_meta(sess: &Session, krate: &hir::Crate,
- name: String) -> LinkMeta {
+ name: &str) -> LinkMeta {
let r = LinkMeta {
- crate_name: name,
+ crate_name: name.to_owned(),
crate_hash: Svh::calculate(&sess.opts.cg.metadata, krate),
};
info!("{:?}", r);
symbol_hasher.input_str(&meta[..]);
}
symbol_hasher.input_str("-");
- symbol_hasher.input_str(&encoder::encoded_ty(tcx, t));
+ symbol_hasher.input(&encoder::encoded_ty(tcx, t));
// Prefix with 'h' so that it never blends into adjacent digits
let mut hash = String::from("h");
hash.push_str(&truncated_hash_result(symbol_hasher));
return result;
}
-pub fn mangle<PI: Iterator<Item=PathElem>>(path: PI,
- hash: Option<&str>) -> String {
+pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
// Follow C++ namespace-mangling style, see
// http://en.wikipedia.org/wiki/Name_mangling for more info.
//
}
// First, connect each component with <len, name> pairs.
- for e in path {
- push(&mut n, &e.name().as_str())
+ for data in path {
+ push(&mut n, &data);
}
match hash {
n
}
-pub fn exported_name(path: PathElems, hash: &str) -> String {
+pub fn exported_name(path: DefPath, hash: &str) -> String {
+ let path = path.into_iter()
+ .map(|e| e.data.as_interned_str());
mangle(path, Some(hash))
}
-pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: PathElems,
+pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: DefPath,
t: Ty<'tcx>, id: ast::NodeId) -> String {
let mut hash = get_symbol_hash(ccx, t);
pub fn mangle_internal_name_by_type_and_seq<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>,
name: &str) -> String {
- let path = [PathName(token::intern(&t.to_string())),
- gensym_name(name)];
+ let path = [token::intern(&t.to_string()).as_str(), gensym_name(name).as_str()];
let hash = get_symbol_hash(ccx, t);
mangle(path.iter().cloned(), Some(&hash[..]))
}
-pub fn mangle_internal_name_by_path_and_seq(path: PathElems, flav: &str) -> String {
- mangle(path.chain(Some(gensym_name(flav))), None)
+pub fn mangle_internal_name_by_path_and_seq(path: DefPath, flav: &str) -> String {
+ let names =
+ path.into_iter()
+ .map(|e| e.data.as_interned_str())
+ .chain(once(gensym_name(flav).as_str())); // append unique version of "flav"
+ mangle(names, None)
}
pub fn get_linker(sess: &Session) -> (String, Command) {
}
config::CrateTypeExecutable => {
let suffix = &sess.target.target.options.exe_suffix;
- let out_filename = outputs.path(OutputTypeExe);
+ let out_filename = outputs.path(OutputType::Exe);
if suffix.is_empty() {
out_filename.to_path_buf()
} else {
outputs: &OutputFilenames,
crate_name: &str) -> PathBuf {
let objects = object_filenames(sess, outputs);
- let out_filename = match outputs.single_output_file {
- Some(ref file) => file.clone(),
- None => filename_for_input(sess, crate_type, crate_name, outputs),
- };
+ let default_filename = filename_for_input(sess, crate_type, crate_name,
+ outputs);
+ let out_filename = outputs.outputs.get(&OutputType::Exe)
+ .and_then(|s| s.to_owned())
+ .or_else(|| outputs.single_output_file.clone())
+ .unwrap_or(default_filename);
// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
// check this already -- however, the Linux linker will happily overwrite a
}
}
- let tmpdir = TempDir::new("rustc").ok().expect("needs a temp dir");
+ let tmpdir = match TempDir::new("rustc") {
+ Ok(tmpdir) => tmpdir,
+ Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
+ };
+
match crate_type {
config::CrateTypeRlib => {
link_rlib(sess, Some(trans), &objects, &out_filename,
fn object_filenames(sess: &Session, outputs: &OutputFilenames) -> Vec<PathBuf> {
(0..sess.opts.cg.codegen_units).map(|i| {
let ext = format!("{}.o", i);
- outputs.temp_path(OutputTypeObject).with_extension(&ext)
+ outputs.temp_path(OutputType::Object).with_extension(&ext)
}).collect()
}
for &(ref l, kind) in sess.cstore.get_used_libraries().borrow().iter() {
match kind {
- cstore::NativeStatic => ab.add_native_library(&l).unwrap(),
+ cstore::NativeStatic => ab.add_native_library(&l),
cstore::NativeFramework | cstore::NativeUnknown => {}
}
}
// See the bottom of back::write::run_passes for an explanation
// of when we do and don't keep .0.bc files around.
let user_wants_numbered_bitcode =
- sess.opts.output_types.contains(&OutputTypeBitcode) &&
+ sess.opts.output_types.contains_key(&OutputType::Bitcode) &&
sess.opts.cg.codegen_units > 1;
if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
remove(sess, &bc_filename);
ab.build();
}
if !sess.target.target.options.no_compiler_rt {
- ab.add_native_library("compiler-rt").unwrap();
+ ab.add_native_library("compiler-rt");
}
let mut all_native_libs = vec![];
let prog = time(sess.time_passes(), "running linker", || cmd.output());
match prog {
Ok(prog) => {
+ fn escape_string(s: &[u8]) -> String {
+ str::from_utf8(s).map(|s| s.to_owned())
+ .unwrap_or_else(|_| {
+ let mut x = "Non-UTF-8 output: ".to_string();
+ x.extend(s.iter()
+ .flat_map(|&b| ascii::escape_default(b))
+ .map(|b| char::from_u32(b as u32).unwrap()));
+ x
+ })
+ }
if !prog.status.success() {
sess.err(&format!("linking with `{}` failed: {}",
pname,
sess.note(&format!("{:?}", &cmd));
let mut output = prog.stderr.clone();
output.push_all(&prog.stdout);
- sess.note(str::from_utf8(&output[..]).unwrap());
+ sess.note(&*escape_string(&output[..]));
sess.abort_if_errors();
}
- info!("linker stderr:\n{}", String::from_utf8(prog.stderr).unwrap());
- info!("linker stdout:\n{}", String::from_utf8(prog.stdout).unwrap());
+ info!("linker stderr:\n{}", escape_string(&prog.stderr[..]));
+ info!("linker stdout:\n{}", escape_string(&prog.stdout[..]));
},
Err(e) => {
sess.fatal(&format!("could not exec the linker `{}`: {}", pname, e));
// default. Note that this does not happen for windows because windows pulls
// in some large number of libraries and I couldn't quite figure out which
// subset we wanted.
- cmd.no_default_libraries();
+ if t.options.no_default_libraries {
+ cmd.no_default_libraries();
+ }
// Take careful note of the ordering of the arguments we pass to the linker
// here. Linkers will assume that things on the left depend on things to the
// such:
//
// 1. The local object that LLVM just generated
- // 2. Upstream rust libraries
- // 3. Local native libraries
+ // 2. Local native libraries
+ // 3. Upstream rust libraries
// 4. Upstream native libraries
//
- // This is generally fairly natural, but some may expect 2 and 3 to be
- // swapped. The reason that all native libraries are put last is that it's
- // not recommended for a native library to depend on a symbol from a rust
- // crate. If this is the case then a staticlib crate is recommended, solving
- // the problem.
- //
- // Additionally, it is occasionally the case that upstream rust libraries
- // depend on a local native library. In the case of libraries such as
- // lua/glfw/etc the name of the library isn't the same across all platforms,
- // so only the consumer crate of a library knows the actual name. This means
- // that downstream crates will provide the #[link] attribute which upstream
- // crates will depend on. Hence local native libraries are after out
- // upstream rust crates.
+ // The rationale behind this ordering is that those items lower down in the
+ // list can't depend on items higher up in the list. For example nothing can
+ // depend on what we just generated (e.g. that'd be a circular dependency).
+ // Upstream rust libraries are not allowed to depend on our local native
+ // libraries as that would violate the structure of the DAG, in that
+ // scenario they are required to link to them as well in a shared fashion.
//
- // In theory this means that a symbol in an upstream native library will be
- // shadowed by a local native library when it wouldn't have been before, but
- // this kind of behavior is pretty platform specific and generally not
- // recommended anyway, so I don't think we're shooting ourself in the foot
- // much with that.
- add_upstream_rust_crates(cmd, sess, dylib, tmpdir);
+ // Note that upstream rust libraries may contain native dependencies as
+ // well, but they also can't depend on what we just started to add to the
+ // link line. And finally upstream native libraries can't depend on anything
+ // in this DAG so far because they're only dylibs and dylibs can only depend
+ // on other dylibs (e.g. other native deps).
add_local_native_libraries(cmd, sess);
+ add_upstream_rust_crates(cmd, sess, dylib, tmpdir);
add_upstream_native_libraries(cmd, sess);
// # Telling the linker what we're doing
use metadata::csearch;
use middle::dependency_format::Linkage;
use session::Session;
-use session::config::DebugInfoLevel::{NoDebugInfo, LimitedDebugInfo, FullDebugInfo};
use session::config::CrateTypeDylib;
use session::config;
use syntax::ast;
}
fn no_default_libraries(&mut self) {
- // Unfortunately right now passing -nodefaultlibs to gcc on windows
- // doesn't work so hot (in terms of native dependencies). This if
- // statement should hopefully be removed one day though!
- if !self.sess.target.target.options.is_like_windows {
- self.cmd.arg("-nodefaultlibs");
- }
+ self.cmd.arg("-nodefaultlibs");
}
fn build_dylib(&mut self, out_filename: &Path) {
}
fn debuginfo(&mut self) {
- match self.sess.opts.debuginfo {
- NoDebugInfo => {
- // Do nothing if debuginfo is disabled
- },
- LimitedDebugInfo |
- FullDebugInfo => {
- // This will cause the Microsoft linker to generate a PDB file
- // from the CodeView line tables in the object files.
- self.cmd.arg("/DEBUG");
- }
- }
+ // This will cause the Microsoft linker to generate a PDB file
+ // from the CodeView line tables in the object files.
+ self.cmd.arg("/DEBUG");
}
fn whole_archives(&mut self) {
use llvm::archive_ro::ArchiveRO;
use llvm::{ModuleRef, TargetMachineRef, True, False};
use rustc::util::common::time;
+use rustc::util::common::path2cstr;
use back::write::{ModuleConfig, with_llvm_pmb};
use libc;
pub fn run(sess: &session::Session, llmod: ModuleRef,
tm: TargetMachineRef, reachable: &[String],
- config: &ModuleConfig) {
+ config: &ModuleConfig,
+ name_extra: &str,
+ output_names: &config::OutputFilenames) {
if sess.opts.cg.prefer_dynamic {
sess.err("cannot prefer dynamic linking when performing LTO");
sess.note("only 'staticlib' and 'bin' outputs are supported with LTO");
}
}
+ if sess.opts.cg.save_temps {
+ let path = output_names.with_extension(&format!("{}.no-opt.lto.bc", name_extra));
+ let cstr = path2cstr(&path);
+ unsafe {
+ llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr());
+ }
+ }
+
// Now we have one massive module inside of llmod. Time to run the
// LTO-specific optimization passes that LLVM provides.
//
use back::link::{get_linker, remove};
use session::config::{OutputFilenames, Passes, SomePasses, AllPasses};
use session::Session;
-use session::config;
+use session::config::{self, OutputType};
use llvm;
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
use llvm::SMDiagnosticRef;
use syntax::diagnostic;
use syntax::diagnostic::{Emitter, Handler, Level};
+use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use std::ptr;
use std::str;
use std::sync::{Arc, Mutex};
use std::thread;
use libc::{self, c_uint, c_int, c_void};
-#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
-pub enum OutputType {
- OutputTypeBitcode,
- OutputTypeAssembly,
- OutputTypeLlvmAssembly,
- OutputTypeObject,
- OutputTypeExe,
-}
-
pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
unsafe {
let cstr = llvm::LLVMRustGetLastError();
plugin_passes: Vec<String>,
// LLVM optimizations for which we want to print remarks.
remark: Passes,
+ // Worker thread number
+ worker: usize,
}
impl<'a> CodegenContext<'a> {
handler: sess.diagnostic().handler(),
plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
remark: sess.opts.cg.remark.clone(),
+ worker: 0,
}
}
}
cgcx.handler.abort_if_errors();
// Finally, run the actual optimization passes
- time(config.time_passes, "llvm function passes", ||
+ time(config.time_passes, &format!("llvm function passes [{}]", cgcx.worker), ||
llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
- time(config.time_passes, "llvm module passes", ||
+ time(config.time_passes, &format!("llvm module passes [{}]", cgcx.worker), ||
llvm::LLVMRunPassManager(mpm, llmod));
// Deallocate managers that we're now done with
match cgcx.lto_ctxt {
Some((sess, reachable)) if sess.lto() => {
time(sess.time_passes(), "all lto passes", ||
- lto::run(sess, llmod, tm, reachable, &config));
+ lto::run(sess, llmod, tm, reachable, &config,
+ &name_extra, &output_names));
if config.emit_lto_bc {
let name = format!("{}.lto.bc", name_extra);
llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
}
- time(config.time_passes, "codegen passes", || {
+ time(config.time_passes, &format!("codegen passes [{}]", cgcx.worker), || {
if config.emit_ir {
let ext = format!("{}.ll", name_extra);
let out = output_names.with_extension(&ext);
pub fn run_passes(sess: &Session,
trans: &CrateTranslation,
- output_types: &[config::OutputType],
+ output_types: &HashMap<OutputType, Option<PathBuf>>,
crate_output: &OutputFilenames) {
// It's possible that we have `codegen_units > 1` but only one item in
// `trans.modules`. We could theoretically proceed and do LTO in that
// archive in order to allow LTO against it.
let needs_crate_bitcode =
sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
- sess.opts.output_types.contains(&config::OutputTypeExe);
+ sess.opts.output_types.contains_key(&OutputType::Exe);
let needs_crate_object =
- sess.opts.output_types.contains(&config::OutputTypeExe);
+ sess.opts.output_types.contains_key(&OutputType::Exe);
if needs_crate_bitcode {
modules_config.emit_bc = true;
}
- for output_type in output_types {
+ for output_type in output_types.keys() {
match *output_type {
- config::OutputTypeBitcode => { modules_config.emit_bc = true; },
- config::OutputTypeLlvmAssembly => { modules_config.emit_ir = true; },
- config::OutputTypeAssembly => {
+ OutputType::Bitcode => { modules_config.emit_bc = true; },
+ OutputType::LlvmAssembly => { modules_config.emit_ir = true; },
+ OutputType::Assembly => {
modules_config.emit_asm = true;
// If we're not using the LLVM assembler, this function
// could be invoked specially with output_type_assembly, so
// in this case we still want the metadata object file.
- if !sess.opts.output_types.contains(&config::OutputTypeAssembly) {
+ if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
metadata_config.emit_obj = true;
}
},
- config::OutputTypeObject => { modules_config.emit_obj = true; },
- config::OutputTypeExe => {
+ OutputType::Object => { modules_config.emit_obj = true; },
+ OutputType::Exe => {
modules_config.emit_obj = true;
metadata_config.emit_obj = true;
},
- config::OutputTypeDepInfo => {}
+ OutputType::DepInfo => {}
}
}
}
};
- let copy_if_one_unit = |ext: &str, output_type: config::OutputType, keep_numbered: bool| {
- // Three cases:
+ let copy_if_one_unit = |ext: &str,
+ output_type: OutputType,
+ keep_numbered: bool| {
if sess.opts.cg.codegen_units == 1 {
// 1) Only one codegen unit. In this case it's no difficulty
// to copy `foo.0.x` to `foo.x`.
// The user just wants `foo.x`, not `foo.0.x`.
remove(sess, &crate_output.with_extension(ext));
}
+ } else if crate_output.outputs.contains_key(&output_type) {
+ // 2) Multiple codegen units, with `--emit foo=some_name`. We have
+ // no good solution for this case, so warn the user.
+ sess.warn(&format!("ignoring emit path because multiple .{} files \
+ were produced", ext));
+ } else if crate_output.single_output_file.is_some() {
+ // 3) Multiple codegen units, with `-o some_name`. We have
+ // no good solution for this case, so warn the user.
+ sess.warn(&format!("ignoring -o because multiple .{} files \
+ were produced", ext));
} else {
- if crate_output.single_output_file.is_some() {
- // 2) Multiple codegen units, with `-o some_name`. We have
- // no good solution for this case, so warn the user.
- sess.warn(&format!("ignoring -o because multiple .{} files were produced",
- ext));
- } else {
- // 3) Multiple codegen units, but no `-o some_name`. We
- // just leave the `foo.0.x` files in place.
- // (We don't have to do any work in this case.)
- }
+ // 4) Multiple codegen units, but no explicit name. We
+ // just leave the `foo.0.x` files in place.
+ // (We don't have to do any work in this case.)
}
};
// to get rid of it.
let mut user_wants_bitcode = false;
let mut user_wants_objects = false;
- for output_type in output_types {
+ for output_type in output_types.keys() {
match *output_type {
- config::OutputTypeBitcode => {
+ OutputType::Bitcode => {
user_wants_bitcode = true;
// Copy to .bc, but always keep the .0.bc. There is a later
// check to figure out if we should delete .0.bc files, or keep
// them for making an rlib.
- copy_if_one_unit("0.bc", config::OutputTypeBitcode, true);
+ copy_if_one_unit("0.bc", OutputType::Bitcode, true);
}
- config::OutputTypeLlvmAssembly => {
- copy_if_one_unit("0.ll", config::OutputTypeLlvmAssembly, false);
+ OutputType::LlvmAssembly => {
+ copy_if_one_unit("0.ll", OutputType::LlvmAssembly, false);
}
- config::OutputTypeAssembly => {
- copy_if_one_unit("0.s", config::OutputTypeAssembly, false);
+ OutputType::Assembly => {
+ copy_if_one_unit("0.s", OutputType::Assembly, false);
}
- config::OutputTypeObject => {
+ OutputType::Object => {
user_wants_objects = true;
- copy_if_one_unit("0.o", config::OutputTypeObject, true);
+ copy_if_one_unit("0.o", OutputType::Object, true);
}
- config::OutputTypeExe |
- config::OutputTypeDepInfo => {}
+ OutputType::Exe |
+ OutputType::DepInfo => {}
}
}
let user_wants_bitcode = user_wants_bitcode;
handler: &diag_handler,
plugin_passes: plugin_passes,
remark: remark,
+ worker: i,
};
loop {
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
let (pname, mut cmd) = get_linker(sess);
- cmd.arg("-c").arg("-o").arg(&outputs.path(config::OutputTypeObject))
- .arg(&outputs.temp_path(config::OutputTypeAssembly));
+ cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
+ .arg(&outputs.temp_path(OutputType::Assembly));
debug!("{:?}", cmd);
match cmd.output() {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_snake_case)]
+
+register_long_diagnostics! {
+
+E0510: r##"
+`return_address` was used in an invalid context. Erroneous code example:
+
+```
+extern "rust-intrinsic" {
+ fn return_address() -> *const u8;
+}
+
+pub unsafe fn by_value() -> i32 {
+ let _ = return_address();
+ // error: invalid use of `return_address` intrinsic: function does
+ // not use out pointer
+ 0
+}
+```
+
+Return values may be stored in a return register(s) or written into a so-called
+out pointer. In case the returned value is too big (this is
+target-ABI-dependent and generally not portable or future proof) to fit into
+the return register(s), the compiler will return the value by writing it into
+space allocated in the caller's stack frame. Example:
+
+```
+extern "rust-intrinsic" {
+ fn return_address() -> *const u8;
+}
+
+pub unsafe fn by_pointer() -> String {
+ let _ = return_address();
+ String::new() // ok!
+}
+```
+"##,
+
+E0511: r##"
+Invalid monomorphization of an intrinsic function was used. Erroneous code
+example:
+
+```
+extern "platform-intrinsic" {
+ fn simd_add<T>(a: T, b: T) -> T;
+}
+
+unsafe { simd_add(0, 1); }
+// error: invalid monomorphization of `simd_add` intrinsic
+```
+
+The generic type has to be a SIMD type. Example:
+
+```
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct i32x1(i32);
+
+extern "platform-intrinsic" {
+ fn simd_add<T>(a: T, b: T) -> T;
+}
+
+unsafe { simd_add(i32x1(0), i32x1(1)); } // ok!
+```
+"##,
+
+E0512: r##"
+Transmute with two differently sized types was attempted. Erroneous code
+example:
+
+```
+extern "rust-intrinsic" {
+ pub fn ctpop8(x: u8) -> u8;
+}
+
+fn main() {
+ unsafe { ctpop8(::std::mem::transmute(0u16)); }
+ // error: transmute called with differently sized types
+}
+```
+
+Please use types with same size or use the expected type directly. Example:
+
+```
+extern "rust-intrinsic" {
+ pub fn ctpop8(x: u8) -> u8;
+}
+
+fn main() {
+ unsafe { ctpop8(::std::mem::transmute(0i8)); } // ok!
+ // or:
+ unsafe { ctpop8(0u8); } // ok!
+}
+```
+"##,
+
+E0515: r##"
+A constant index expression was out of bounds. Erroneous code example:
+
+```
+let x = &[0, 1, 2][7]; // error: const index-expr is out of bounds
+```
+
+Please specify a valid index (not inferior to 0 or superior to array length).
+Example:
+
+```
+let x = &[0, 1, 2][2]; // ok
+```
+"##,
+
+}
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(const_fn)]
+#![feature(custom_attribute)]
+#![allow(unused_attributes)]
#![feature(iter_cmp)]
#![feature(iter_arith)]
#![feature(libc)]
-#![feature(path_ext)]
-#![feature(path_ext)]
-#![feature(path_relative_from)]
#![feature(path_relative_from)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(unicode)]
-#![feature(unicode)]
#![feature(vec_push_all)]
#![allow(trivial_casts)]
pub mod msvc;
}
+pub mod diagnostics;
+
pub mod trans;
pub mod save;
use syntax::print::pprust::{path_to_string, ty_to_string};
use syntax::ptr::P;
-use rustc_front::lowering::lower_expr;
+use rustc_front::lowering::{lower_expr, LoweringContext};
use super::span_utils::SpanUtils;
use super::recorder::{Recorder, FmtStrs};
data
} else {
$this.sess.span_bug($sp, &format!("unexpected data kind: {:?}", $id));
- };
+ }
};
}
save_ctxt: SaveContext<'l, 'tcx>,
sess: &'l Session,
tcx: &'l ty::ctxt<'tcx>,
- analysis: &'l ty::CrateAnalysis,
+ analysis: &'l ty::CrateAnalysis<'l>,
span: SpanUtils<'l>,
- fmt: FmtStrs<'l>,
+ fmt: FmtStrs<'l, 'tcx>,
cur_scope: NodeId,
}
impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
pub fn new(tcx: &'l ty::ctxt<'tcx>,
- analysis: &'l ty::CrateAnalysis,
+ lcx: &'l LoweringContext<'l>,
+ analysis: &'l ty::CrateAnalysis<'l>,
output_file: Box<File>)
-> DumpCsvVisitor<'l, 'tcx> {
let span_utils = SpanUtils::new(&tcx.sess);
DumpCsvVisitor {
sess: &tcx.sess,
tcx: tcx,
- save_ctxt: SaveContext::from_span_utils(tcx, span_utils.clone()),
+ save_ctxt: SaveContext::from_span_utils(tcx, lcx, span_utils.clone()),
analysis: analysis,
span: span_utils.clone(),
- fmt: FmtStrs::new(box Recorder { out: output_file, dump_spans: false },
- span_utils),
+ fmt: FmtStrs::new(box Recorder {
+ out: output_file,
+ dump_spans: false,
+ },
+ span_utils,
+ tcx),
cur_scope: 0,
}
}
// always using the first ones. So, only error out if we don't have enough spans.
// What could go wrong...?
if spans.len() < path.segments.len() {
- error!("Mis-calculated spans for path '{}'. \
- Found {} spans, expected {}. Found spans:",
- path_to_string(path), spans.len(), path.segments.len());
+ error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
+ path_to_string(path),
+ spans.len(),
+ path.segments.len());
for s in &spans {
let loc = self.sess.codemap().lookup_char_pos(s.lo);
error!(" '{}' in {}, line {}",
- self.span.snippet(*s), loc.file.name, loc.line);
+ self.span.snippet(*s),
+ loc.file.name,
+ loc.line);
}
return vec!();
}
} else {
qualname.clone()
};
- self.fmt.sub_mod_ref_str(path.span,
- *span,
- &qualname,
- self.cur_scope);
+ self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope);
}
}
} else {
qualname.clone()
};
- self.fmt.sub_mod_ref_str(path.span,
- *span,
- &qualname,
- self.cur_scope);
+ self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope);
}
}
// write the trait part of the sub-path
let (ref span, ref qualname) = sub_paths[len-2];
- self.fmt.sub_type_ref_str(path.span,
- *span,
- &qualname);
+ self.fmt.sub_type_ref_str(path.span, *span, &qualname);
// write the other sub-paths
if len <= 2 {
}
let sub_paths = &sub_paths[..len-2];
for &(ref span, ref qualname) in sub_paths {
- self.fmt.sub_mod_ref_str(path.span,
- *span,
- &qualname,
- self.cur_scope);
+ self.fmt.sub_mod_ref_str(path.span, *span, &qualname, self.cur_scope);
}
}
fn lookup_type_ref(&self, ref_id: NodeId) -> Option<DefId> {
if !self.tcx.def_map.borrow().contains_key(&ref_id) {
self.sess.bug(&format!("def_map has no key for {} in lookup_type_ref",
- ref_id));
+ ref_id));
}
let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
- def::DefPrimTy(_) => None,
+ def::DefPrimTy(..) => None,
+ def::DefSelfTy(..) => None,
_ => Some(def.def_id()),
}
}
fn lookup_def_kind(&self, ref_id: NodeId, span: Span) -> Option<recorder::Row> {
let def_map = self.tcx.def_map.borrow();
if !def_map.contains_key(&ref_id) {
- self.sess.span_bug(span, &format!("def_map has no key for {} in lookup_def_kind",
- ref_id));
+ self.sess.span_bug(span,
+ &format!("def_map has no key for {} in lookup_def_kind",
+ ref_id));
}
let def = def_map.get(&ref_id).unwrap().full_def();
match def {
def::DefStatic(_, _) |
def::DefConst(_) |
def::DefAssociatedConst(..) |
- def::DefLocal(_) |
+ def::DefLocal(..) |
def::DefVariant(_, _, _) |
def::DefUpvar(..) => Some(recorder::VarRef),
def::DefFn(..) => Some(recorder::FnRef),
def::DefSelfTy(..) |
- def::DefRegion(_) |
def::DefLabel(_) |
def::DefTyParam(..) |
def::DefUse(_) |
def::DefMethod(..) |
def::DefPrimTy(_) => {
- self.sess.span_bug(span, &format!("lookup_def_kind for unexpected item: {:?}",
- def));
+ self.sess.span_bug(span,
+ &format!("lookup_def_kind for unexpected item: {:?}", def));
}
}
}
self.nest(id, |v| v.visit_block(body));
}
- self.process_generic_params(&sig.generics,
- span,
- &method_data.qualname,
- id);
+ self.process_generic_params(&sig.generics, span, &method_data.qualname, id);
}
fn process_trait_ref(&mut self, trait_ref: &ast::TraitRef) {
// However full span is the entire enum/fn/struct block, so we only want
// the first few to match the number of generics we're looking for.
let param_sub_spans = self.span.spans_for_ty_params(full_span,
- (generics.ty_params.len() as isize));
+ (generics.ty_params.len() as isize));
for (param, param_ss) in generics.ty_params.iter().zip(param_sub_spans) {
// Append $id to name to make sure each one is unique
let name = format!("{}::{}${}",
prefix,
escape(self.span.snippet(param_ss)),
id);
- self.fmt.typedef_str(full_span,
- Some(param_ss),
- param.id,
- &name,
- "");
+ self.fmt.typedef_str(full_span, Some(param_ss), param.id, &name, "");
}
self.visit_generics(generics);
}
fn process_const(&mut self,
id: ast::NodeId,
- ident: &ast::Ident,
+ name: ast::Name,
span: Span,
typ: &ast::Ty,
expr: &ast::Expr) {
let qualname = format!("::{}", self.tcx.map.path_to_string(id));
- let sub_span = self.span.sub_span_after_keyword(span,
- keywords::Const);
+ let sub_span = self.span.sub_span_after_keyword(span, keywords::Const);
self.fmt.static_str(span,
sub_span,
id,
- &ident.name.as_str(),
+ &name.as_str(),
&qualname,
&self.span.snippet(expr.span),
&ty_to_string(&*typ),
fn process_struct(&mut self,
item: &ast::Item,
- def: &ast::StructDef,
+ def: &ast::VariantData,
ty_params: &ast::Generics) {
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
- let ctor_id = match def.ctor_id {
- Some(node_id) => node_id,
- None => ast::DUMMY_NODE_ID,
- };
let val = self.span.snippet(item.span);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Struct);
self.fmt.struct_str(item.span,
sub_span,
item.id,
- ctor_id,
+ def.id(),
&qualname,
self.cur_scope,
&val);
// fields
- for field in &def.fields {
+ for field in def.fields() {
self.process_struct_field_def(field, item.id);
self.visit_ty(&field.node.ty);
}
qualname.push_str("::");
qualname.push_str(name);
let val = self.span.snippet(variant.span);
- match variant.node.kind {
- ast::TupleVariantKind(ref args) => {
- // first ident in span is the variant's name
- self.fmt.tuple_variant_str(variant.span,
- self.span.span_for_first_ident(variant.span),
- variant.node.id,
- name,
- &qualname,
- &enum_data.qualname,
- &val,
- enum_data.id);
- for arg in args {
- self.visit_ty(&*arg.ty);
- }
- }
- ast::StructVariantKind(ref struct_def) => {
- let ctor_id = match struct_def.ctor_id {
- Some(node_id) => node_id,
- None => ast::DUMMY_NODE_ID,
- };
- self.fmt.struct_variant_str(variant.span,
- self.span.span_for_first_ident(variant.span),
- variant.node.id,
- ctor_id,
- &qualname,
- &enum_data.qualname,
- &val,
- enum_data.id);
-
- for field in &struct_def.fields {
- self.process_struct_field_def(field, variant.node.id);
- self.visit_ty(&*field.node.ty);
- }
- }
+
+ self.fmt.struct_variant_str(variant.span,
+ self.span.span_for_first_ident(variant.span),
+ variant.node.data.id(),
+ variant.node.data.id(),
+ &qualname,
+ &enum_data.qualname,
+ &val,
+ enum_data.id);
+
+ for field in variant.node.data.fields() {
+ self.process_struct_field_def(field, variant.node.data.id());
+ self.visit_ty(&*field.node.ty);
}
}
self.process_generic_params(ty_params, item.span, &enum_data.qualname, enum_data.id);
sub_span,
id,
self.cur_scope);
- self.fmt.inherit_str(trait_ref.path.span,
- sub_span,
- id,
- item.id);
+ self.fmt.inherit_str(trait_ref.path.span, sub_span, id, item.id);
}
None => (),
}
Some(pd) => pd,
None => {
self.tcx.sess.span_bug(path.span,
- &format!("Unexpected def kind while looking \
- up path in `{}`",
+ &format!("Unexpected def kind while looking up path in \
+ `{}`",
self.span.snippet(path.span)))
}
};
match path_data {
Data::VariableRefData(ref vrd) => {
self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
- path.span,
- Some(vrd.span),
- vrd.ref_id,
- vrd.scope);
+ path.span,
+ Some(vrd.span),
+ vrd.ref_id,
+ vrd.scope);
}
Data::TypeRefData(ref trd) => {
mcd.scope);
}
Data::FunctionCallData(fcd) => {
- self.fmt.fn_call_str(path.span,
- Some(fcd.span),
- fcd.ref_id,
- fcd.scope);
+ self.fmt.fn_call_str(path.span, Some(fcd.span), fcd.ref_id, fcd.scope);
}
_ => {
self.sess.span_bug(path.span,
}
}
}
- def::DefLocal(_) |
+ def::DefLocal(..) |
def::DefStatic(_,_) |
def::DefConst(..) |
def::DefAssociatedConst(..) |
continue;
}
- let field_data = self.save_ctxt.get_field_ref_data(field,
- variant,
- scope);
+ let field_data = self.save_ctxt.get_field_ref_data(field, variant, scope);
self.fmt.ref_str(recorder::VarRef,
field.ident.span,
Some(field_data.span),
}
}
- visit::walk_expr_opt(self, base)
+ walk_list!(self, visit_expr, base);
}
fn process_method_call(&mut self, ex: &ast::Expr, args: &Vec<P<ast::Expr>>) {
}
// walk receiver and args
- visit::walk_exprs(self, &args);
+ walk_list!(self, visit_expr, args);
}
fn process_pat(&mut self, p: &ast::Pat) {
let sub_span = self.span.span_for_first_ident(span);
if let Some(f) = variant.find_field_named(field.ident.name) {
- self.fmt.ref_str(recorder::VarRef,
- span,
- sub_span,
- f.did,
- self.cur_scope);
+ self.fmt.ref_str(recorder::VarRef, span, sub_span, f.did, self.cur_scope);
}
self.visit_pat(&field.pat);
}
_ => visit::walk_pat(self, p),
}
}
+
+
+ fn process_var_decl(&mut self, p: &ast::Pat, value: String) {
+ // The local could declare multiple new vars, we must walk the
+ // pattern and collect them all.
+ let mut collector = PathCollector::new();
+ collector.visit_pat(&p);
+ self.visit_pat(&p);
+
+ for &(id, ref p, immut, _) in &collector.collected_paths {
+ let value = if immut == ast::MutImmutable {
+ value.to_string()
+ } else {
+ "<mutable>".to_string()
+ };
+ let types = self.tcx.node_types();
+ let typ = types.get(&id).unwrap().to_string();
+ // Get the span only for the name of the variable (I hope the path
+ // is only ever a variable name, but who knows?).
+ let sub_span = self.span.span_for_last_ident(p.span);
+ // Rust uses the id of the pattern for var lookups, so we'll use it too.
+ self.fmt.variable_str(p.span,
+ sub_span,
+ id,
+ &path_to_string(p),
+ &value,
+ &typ);
+ }
+ }
}
impl<'l, 'tcx, 'v> Visitor<'v> for DumpCsvVisitor<'l, 'tcx> {
// 'use' always introduces an alias, if there is not an explicit
// one, there is an implicit one.
- let sub_span =
- match self.span.sub_span_after_keyword(use_item.span, keywords::As) {
- Some(sub_span) => Some(sub_span),
- None => sub_span,
- };
+ let sub_span = match self.span.sub_span_after_keyword(use_item.span,
+ keywords::As) {
+ Some(sub_span) => Some(sub_span),
+ None => sub_span,
+ };
self.fmt.use_alias_str(path.span,
sub_span,
}
}
- let sub_span = self.span.sub_span_of_token(path.span,
- token::BinOp(token::Star));
+ let sub_span = self.span
+ .sub_span_of_token(path.span, token::BinOp(token::Star));
self.fmt.use_glob_str(path.span,
sub_span,
item.id,
match self.lookup_type_ref(id) {
Some(def_id) => match self.lookup_def_kind(id, plid.span) {
Some(kind) => {
- self.fmt.ref_str(
- kind, plid.span,
- Some(plid.span),
- def_id, self.cur_scope);
+ self.fmt.ref_str(kind,
+ plid.span,
+ Some(plid.span),
+ def_id,
+ self.cur_scope);
}
None => (),
},
self.process_static_or_const_item(item, typ, expr),
ast::ItemConst(ref typ, ref expr) =>
self.process_static_or_const_item(item, &typ, &expr),
- ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
+ ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
ast::ItemImpl(_, _,
ref ty_params,
ref trait_ref,
ref typ,
ref impl_items) => {
- self.process_impl(item,
- ty_params,
- trait_ref,
- &typ,
- impl_items)
+ self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
}
ast::ItemTrait(_, ref generics, ref trait_refs, ref methods) =>
self.process_trait(item, generics, trait_refs, methods),
let qualname = format!("::{}", self.tcx.map.path_to_string(item.id));
let value = ty_to_string(&**ty);
let sub_span = self.span.sub_span_after_keyword(item.span, keywords::Type);
- self.fmt.typedef_str(item.span,
- sub_span,
- item.id,
- &qualname,
- &value);
+ self.fmt.typedef_str(item.span, sub_span, item.id, &qualname, &value);
self.visit_ty(&**ty);
self.process_generic_params(ty_params, item.span, &qualname, item.id);
fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
match trait_item.node {
ast::ConstTraitItem(ref ty, Some(ref expr)) => {
- self.process_const(trait_item.id, &trait_item.ident,
- trait_item.span, &*ty, &*expr);
+ self.process_const(trait_item.id,
+ trait_item.ident.name,
+ trait_item.span,
+ &*ty,
+ &*expr);
}
ast::MethodTraitItem(ref sig, ref body) => {
self.process_method(sig,
fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
match impl_item.node {
ast::ConstImplItem(ref ty, ref expr) => {
- self.process_const(impl_item.id, &impl_item.ident,
- impl_item.span, &ty, &expr);
+ self.process_const(impl_item.id,
+ impl_item.ident.name,
+ impl_item.span,
+ &ty,
+ &expr);
}
ast::MethodImplItem(ref sig, ref body) => {
self.process_method(sig,
match self.lookup_type_ref(t.id) {
Some(id) => {
let sub_span = self.span.sub_span_for_type_name(t.span);
- self.fmt.ref_str(recorder::TypeRef,
- t.span,
- sub_span,
- id,
- self.cur_scope);
+ self.fmt.ref_str(recorder::TypeRef, t.span, sub_span, id, self.cur_scope);
}
None => (),
}
visit::walk_expr(self, ex);
}
ast::ExprStruct(ref path, ref fields, ref base) => {
- let hir_expr = lower_expr(ex);
+ let hir_expr = lower_expr(self.save_ctxt.lcx, ex);
let adt = self.tcx.expr_ty(&hir_expr).ty_adt_def().unwrap();
let def = self.tcx.resolve_expr(&hir_expr);
- self.process_struct_lit(ex,
- path,
- fields,
- adt.variant_of_def(def),
- base)
+ self.process_struct_lit(ex, path, fields, adt.variant_of_def(def), base)
}
ast::ExprMethodCall(_, _, ref args) => self.process_method_call(ex, args),
ast::ExprField(ref sub_ex, _) => {
self.visit_expr(&**sub_ex);
- let hir_node = self.tcx.map.expect_expr(sub_ex.id);
+ let hir_node = lower_expr(self.save_ctxt.lcx, sub_ex);
let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
match *ty {
ty::TyStruct(def, _) => {
}
ty::TyTuple(_) => {}
_ => self.sess.span_bug(ex.span,
- &format!("Expected struct or tuple \
- type, found {:?}", ty)),
+ &format!("Expected struct or tuple type, found {:?}",
+ ty)),
}
}
ast::ExprClosure(_, ref decl, ref body) => {
// walk the body
self.nest(ex.id, |v| v.visit_block(&**body));
}
+ ast::ExprForLoop(ref pattern, ref subexpression, ref block, _) |
+ ast::ExprWhileLet(ref pattern, ref subexpression, ref block, _) => {
+ let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi));
+ self.process_var_decl(pattern, value);
+ visit::walk_expr(self, subexpression);
+ visit::walk_block(self, block);
+ }
+ ast::ExprIfLet(ref pattern, ref subexpression, ref block, ref opt_else) => {
+ let value = self.span.snippet(mk_sp(ex.span.lo, subexpression.span.hi));
+ self.process_var_decl(pattern, value);
+ visit::walk_expr(self, subexpression);
+ visit::walk_block(self, block);
+ opt_else.as_ref().map(|el| visit::walk_expr(self, el));
+ }
_ => {
visit::walk_expr(self, ex)
}
let def_map = self.tcx.def_map.borrow();
if !def_map.contains_key(&id) {
self.sess.span_bug(p.span,
- &format!("def_map has no key for {} in visit_arm",
- id));
+ &format!("def_map has no key for {} in visit_arm", id));
}
let def = def_map.get(&id).unwrap().full_def();
match def {
- def::DefLocal(id) => {
+ def::DefLocal(_, id) => {
let value = if immut == ast::MutImmutable {
self.span.snippet(p.span).to_string()
} else {
"<mutable>".to_string()
};
- assert!(p.segments.len() == 1, "qualified path for local variable def in arm");
- self.fmt.variable_str(p.span,
- Some(p.span),
- id,
- &path_to_string(p),
- &value,
- "")
+ assert!(p.segments.len() == 1,
+ "qualified path for local variable def in arm");
+ self.fmt.variable_str(p.span, Some(p.span), id, &path_to_string(p), &value, "")
}
def::DefVariant(..) | def::DefTy(..) | def::DefStruct(..) => {
paths_to_process.push((id, p.clone(), Some(ref_kind)))
for &(id, ref path, ref_kind) in &paths_to_process {
self.process_path(id, path, ref_kind);
}
- visit::walk_expr_opt(self, &arm.guard);
+ walk_list!(self, visit_expr, &arm.guard);
self.visit_expr(&arm.body);
}
return
}
- // The local could declare multiple new vars, we must walk the
- // pattern and collect them all.
- let mut collector = PathCollector::new();
- collector.visit_pat(&l.pat);
- self.visit_pat(&l.pat);
-
let value = self.span.snippet(l.span);
-
- for &(id, ref p, immut, _) in &collector.collected_paths {
- let value = if immut == ast::MutImmutable {
- value.to_string()
- } else {
- "<mutable>".to_string()
- };
- let types = self.tcx.node_types();
- let typ = types.get(&id).unwrap().to_string();
- // Get the span only for the name of the variable (I hope the path
- // is only ever a variable name, but who knows?).
- let sub_span = self.span.span_for_last_ident(p.span);
- // Rust uses the id of the pattern for var lookups, so we'll use it too.
- self.fmt.variable_str(p.span,
- sub_span,
- id,
- &path_to_string(p),
- &value,
- &typ);
- }
+ self.process_var_decl(&l.pat, value);
// Just walk the initialiser and type (don't want to walk the pattern again).
- visit::walk_ty_opt(self, &l.ty);
- visit::walk_expr_opt(self, &l.init);
+ walk_list!(self, visit_ty, &l.ty);
+ walk_list!(self, visit_expr, &l.init);
}
}
+
use middle::ty;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use std::env;
use std::fs::{self, File};
use rustc_front;
use rustc::front::map::NodeItem;
-use rustc_front::hir;
+use rustc_front::{hir, lowering};
-use syntax::attr;
use syntax::ast::{self, NodeId};
use syntax::ast_util;
use syntax::codemap::*;
pub struct SaveContext<'l, 'tcx: 'l> {
tcx: &'l ty::ctxt<'tcx>,
+ lcx: &'l lowering::LoweringContext<'l>,
span_utils: SpanUtils<'l>,
}
impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
- pub fn new(tcx: &'l ty::ctxt<'tcx>) -> SaveContext<'l, 'tcx> {
+ pub fn new(tcx: &'l ty::ctxt<'tcx>,
+ lcx: &'l lowering::LoweringContext<'l>)
+ -> SaveContext<'l, 'tcx> {
let span_utils = SpanUtils::new(&tcx.sess);
- SaveContext::from_span_utils(tcx, span_utils)
+ SaveContext::from_span_utils(tcx, lcx, span_utils)
}
pub fn from_span_utils(tcx: &'l ty::ctxt<'tcx>,
+ lcx: &'l lowering::LoweringContext<'l>,
span_utils: SpanUtils<'l>)
-> SaveContext<'l, 'tcx> {
- SaveContext { tcx: tcx, span_utils: span_utils }
+ SaveContext {
+ tcx: tcx,
+ lcx: lcx,
+ span_utils: span_utils,
+ }
}
// List external crates used by the current crate.
let mut result = Vec::new();
self.tcx.sess.cstore.iter_crate_data(|n, cmd| {
- result.push(CrateData { name: cmd.name.clone(), number: n });
+ result.push(CrateData {
+ name: cmd.name.clone(),
+ number: n,
+ });
});
result
// Common case impl for a struct or something basic.
ast::TyPath(None, ref path) => {
sub_span = self.span_utils.sub_span_for_type_name(path.span).unwrap();
- type_data = self.lookup_ref_id(typ.id).map(|id| TypeRefData {
- span: sub_span,
- scope: parent,
- ref_id: id,
+ type_data = self.lookup_ref_id(typ.id).map(|id| {
+ TypeRefData {
+ span: sub_span,
+ scope: parent,
+ ref_id: id,
+ }
});
}
_ => {
}
}
- let trait_data =
- trait_ref.as_ref().and_then(|tr| self.get_trait_ref_data(tr, parent));
+ let trait_data = trait_ref.as_ref()
+ .and_then(|tr| self.get_trait_ref_data(tr, parent));
Data::ImplData(ImplData {
id: item.id,
pub fn get_field_data(&self, field: &ast::StructField, scope: NodeId) -> Option<VariableData> {
match field.node.kind {
ast::NamedField(ident, _) => {
- let qualname = format!("::{}::{}",
- self.tcx.map.path_to_string(scope),
- ident);
- let typ = self.tcx.node_types().get(&field.node.id).unwrap()
- .to_string();
+ let qualname = format!("::{}::{}", self.tcx.map.path_to_string(scope), ident);
+ let typ = self.tcx.node_types().get(&field.node.id).unwrap().to_string();
let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
Some(VariableData {
id: field.node.id,
pub fn get_method_data(&self, id: ast::NodeId, name: ast::Name, span: Span) -> FunctionData {
// The qualname for a method is the trait name or name of the struct in an impl in
// which the method is declared in, followed by the method's name.
- let qualname = match self.tcx.impl_of_method(DefId::local(id)) {
- Some(impl_id) => match self.tcx.map.get(impl_id.node) {
- NodeItem(item) => {
+ let qualname = match self.tcx.impl_of_method(self.tcx.map.local_def_id(id)) {
+ Some(impl_id) => match self.tcx.map.get_if_local(impl_id) {
+ Some(NodeItem(item)) => {
match item.node {
hir::ItemImpl(_, _, _, _, ref ty, _) => {
let mut result = String::from("<");
result.push_str(&rustc_front::print::pprust::ty_to_string(&**ty));
- match self.tcx.trait_of_item(DefId::local(id)) {
+ match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
Some(def_id) => {
result.push_str(" as ");
- result.push_str(
- &self.tcx.item_path_str(def_id));
+ result.push_str(&self.tcx.item_path_str(def_id));
}
None => {}
}
}
_ => {
self.tcx.sess.span_bug(span,
- &format!("Container {} for method {} not an impl?",
- impl_id.node, id));
+ &format!("Container {:?} for method {} not \
+ an impl?",
+ impl_id,
+ id));
}
}
}
- _ => {
+ r => {
self.tcx.sess.span_bug(span,
- &format!("Container {} for method {} is not a node item {:?}",
- impl_id.node, id, self.tcx.map.get(impl_id.node)));
+ &format!("Container {:?} for method {} is not a node \
+ item {:?}",
+ impl_id,
+ id,
+ r));
}
},
- None => match self.tcx.trait_of_item(DefId::local(id)) {
+ None => match self.tcx.trait_of_item(self.tcx.map.local_def_id(id)) {
Some(def_id) => {
- match self.tcx.map.get(def_id.node) {
- NodeItem(_) => {
+ match self.tcx.map.get_if_local(def_id) {
+ Some(NodeItem(_)) => {
format!("::{}", self.tcx.item_path_str(def_id))
}
- _ => {
+ r => {
self.tcx.sess.span_bug(span,
- &format!("Could not find container {} for method {}",
- def_id.node, id));
+ &format!("Could not find container {:?} for \
+ method {}, got {:?}",
+ def_id,
+ id,
+ r));
}
}
}
None => {
self.tcx.sess.span_bug(span,
- &format!("Could not find container for method {}", id));
+ &format!("Could not find container for method {}", id));
}
},
};
let qualname = format!("{}::{}", qualname, name);
- let decl_id = self.tcx.trait_item_of_item(DefId::local(id))
- .and_then(|new_id| {
- let def_id = new_id.def_id();
- if def_id.node != 0 && def_id != DefId::local(id) {
- Some(def_id)
- } else {
- None
- }
- });
+ let def_id = self.tcx.map.local_def_id(id);
+ let decl_id = self.tcx.trait_item_of_item(def_id).and_then(|new_id| {
+ let new_def_id = new_id.def_id();
+ if new_def_id != def_id {
+ Some(new_def_id)
+ } else {
+ None
+ }
+ });
let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
pub fn get_expr_data(&self, expr: &ast::Expr) -> Option<Data> {
match expr.node {
ast::ExprField(ref sub_ex, ident) => {
- let hir_node = self.tcx.map.expect_expr(sub_ex.id);
+ let hir_node = lowering::lower_expr(self.lcx, sub_ex);
let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
match *ty {
ty::TyStruct(def, _) => {
}
}
ast::ExprStruct(ref path, _, _) => {
- let hir_node = self.tcx.map.expect_expr(expr.id);
- let ty = &self.tcx.expr_ty_adjusted(hir_node).sty;
+ let hir_node = lowering::lower_expr(self.lcx, expr);
+ let ty = &self.tcx.expr_ty_adjusted(&hir_node).sty;
match *ty {
ty::TyStruct(def, _) => {
let sub_span = self.span_utils.span_for_last_ident(path.span);
let ti = self.tcx.impl_or_trait_item(decl_id);
match ti.container() {
ty::TraitContainer(def_id) => {
- self.tcx.trait_items(def_id)
+ self.tcx
+ .trait_items(def_id)
.iter()
- .find(|mr| {
- mr.name() == ti.name() && self.trait_method_has_body(mr)
- })
+ .find(|mr| mr.name() == ti.name() && self.trait_method_has_body(mr))
.map(|mr| mr.def_id())
}
ty::ImplContainer(def_id) => {
.unwrap()
.iter()
.find(|mr| {
- self.tcx.impl_or_trait_item(mr.def_id()).name()
- == ti.name()
- })
+ self.tcx.impl_or_trait_item(mr.def_id()).name() ==
+ ti.name()
+ })
.unwrap()
.def_id())
}
fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool {
let def_id = mr.def_id();
- if def_id.krate != LOCAL_CRATE {
- return false;
- }
-
- let trait_item = self.tcx.map.expect_trait_item(def_id.node);
- if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
- true
+ if let Some(node_id) = self.tcx.map.as_local_node_id(def_id) {
+ let trait_item = self.tcx.map.expect_trait_item(node_id);
+ if let hir::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node {
+ true
+ } else {
+ false
+ }
} else {
false
}
}
let def = self.tcx.def_map.borrow().get(&ref_id).unwrap().full_def();
match def {
- def::DefPrimTy(_) => None,
+ def::DefPrimTy(_) | def::DefSelfTy(..) => None,
_ => Some(def.def_id()),
}
}
match p.node {
ast::PatStruct(ref path, _, _) => {
- self.collected_paths.push((p.id,
- path.clone(),
- ast::MutMutable,
- recorder::TypeRef));
+ self.collected_paths.push((p.id, path.clone(), ast::MutMutable, recorder::TypeRef));
}
ast::PatEnum(ref path, _) |
ast::PatQPath(_, ref path) => {
}
}
-pub fn process_crate(tcx: &ty::ctxt,
- krate: &ast::Crate,
- analysis: &ty::CrateAnalysis,
- odir: Option<&Path>) {
+pub fn process_crate<'l, 'tcx>(tcx: &'l ty::ctxt<'tcx>,
+ lcx: &'l lowering::LoweringContext<'l>,
+ krate: &ast::Crate,
+ analysis: &ty::CrateAnalysis,
+ cratename: &str,
+ odir: Option<&Path>) {
if generated_code(krate.span) {
return;
}
assert!(analysis.glob_map.is_some());
- let cratename = match attr::find_crate_name(&krate.attrs) {
- Some(name) => name.to_string(),
- None => {
- info!("Could not find crate name, using 'unknown_crate'");
- String::from("unknown_crate")
- }
- };
info!("Dumping crate {}", cratename);
if let Err(e) = fs::create_dir_all(&root_path) {
tcx.sess.err(&format!("Could not create directory {}: {}",
- root_path.display(), e));
+ root_path.display(),
+ e));
}
{
}
// Create output file.
- let mut out_name = cratename.clone();
+ let mut out_name = cratename.to_owned();
out_name.push_str(".csv");
root_path.push(&out_name);
let output_file = match File::create(&root_path) {
};
root_path.pop();
- let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, analysis, output_file);
+ let mut visitor = dump_csv::DumpCsvVisitor::new(tcx, lcx, analysis, output_file);
- visitor.dump_crate_info(&cratename, krate);
+ visitor.dump_crate_info(cratename, krate);
visit::walk_crate(&mut visitor, krate);
}
use super::escape;
use super::span_utils::SpanUtils;
-use middle::def_id::DefId;
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::{CRATE_DEF_INDEX, DefId};
+use middle::ty;
use std::io::Write;
use syntax::ast::NodeId;
use syntax::codemap::*;
-const ZERO_DEF_ID: DefId = DefId { node: 0, krate: 0 };
+const CRATE_ROOT_DEF_ID: DefId = DefId {
+ krate: LOCAL_CRATE,
+ index: CRATE_DEF_INDEX,
+};
pub struct Recorder {
// output file
pub fn dump_span(&mut self, su: SpanUtils, kind: &str, span: Span, _sub_span: Option<Span>) {
assert!(self.dump_spans);
let result = format!("span,kind,{},{},text,\"{}\"\n",
- kind, su.extent_str(span), escape(su.snippet(span)));
+ kind,
+ su.extent_str(span),
+ escape(su.snippet(span)));
self.record(&result[..]);
}
}
-pub struct FmtStrs<'a> {
+pub struct FmtStrs<'a, 'tcx: 'a> {
pub recorder: Box<Recorder>,
span: SpanUtils<'a>,
+ tcx: &'a ty::ctxt<'tcx>,
}
macro_rules! s { ($e:expr) => { format!("{}", $e) }}
FnRef,
}
-impl<'a> FmtStrs<'a> {
- pub fn new(rec: Box<Recorder>, span: SpanUtils<'a>) -> FmtStrs<'a> {
- FmtStrs { recorder: rec, span: span }
+impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> {
+ pub fn new(rec: Box<Recorder>,
+ span: SpanUtils<'a>,
+ tcx: &'a ty::ctxt<'tcx>)
+ -> FmtStrs<'a, 'tcx> {
+ FmtStrs {
+ recorder: rec,
+ span: span,
+ tcx: tcx,
+ }
+ }
+
+ // Emitted ids are used to cross-reference items across crates. DefIds and
+ // NodeIds do not usually correspond in any way. The strategy is to use the
+ // index from the DefId as a crate-local id. However, within a crate, DefId
+ // indices and NodeIds can overlap. So, we must adjust the NodeIds. If an
+ // item can be identified by a DefId as well as a NodeId, then we use the
+ // DefId index as the id. If it can't, then we have to use the NodeId, but
+ // need to adjust it so it will not clash with any possible DefId index.
+ fn normalize_node_id(&self, id: NodeId) -> usize {
+ match self.tcx.map.opt_local_def_id(id) {
+ Some(id) => id.index.as_usize(),
+ None => id as usize + self.tcx.map.num_local_def_ids()
+ }
}
// A map from kind of item to a tuple of
fn lookup_row(r: Row) -> (&'static str, Vec<&'static str>, bool, bool) {
match r {
Variable => ("variable",
- vec!("id","name","qualname","value","type","scopeid"),
+ vec!("id", "name", "qualname", "value", "type", "scopeid"),
true,
true),
- Enum => ("enum", vec!("id","qualname","scopeid","value"), true, true),
+ Enum => ("enum",
+ vec!("id", "qualname", "scopeid", "value"),
+ true,
+ true),
Variant => ("variant",
- vec!("id","name","qualname","type","value","scopeid"),
+ vec!("id", "name", "qualname", "type", "value", "scopeid"),
true,
true),
VariantStruct => ("variant_struct",
- vec!("id","ctor_id","qualname","type","value","scopeid"),
+ vec!("id", "ctor_id", "qualname", "type", "value", "scopeid"),
true,
true),
Function => ("function",
- vec!("id","qualname","declid","declidcrate","scopeid"),
+ vec!("id", "qualname", "declid", "declidcrate", "scopeid"),
true,
true),
- MethodDecl => ("method_decl", vec!("id","qualname","scopeid"), true, true),
- Struct => ("struct", vec!("id","ctor_id","qualname","scopeid","value"), true, true),
- Trait => ("trait", vec!("id","qualname","scopeid","value"), true, true),
+ MethodDecl => ("method_decl",
+ vec!("id", "qualname", "scopeid"),
+ true,
+ true),
+ Struct => ("struct",
+ vec!("id", "ctor_id", "qualname", "scopeid", "value"),
+ true,
+ true),
+ Trait => ("trait",
+ vec!("id", "qualname", "scopeid", "value"),
+ true,
+ true),
Impl => ("impl",
- vec!("id","refid","refidcrate","traitid","traitidcrate","scopeid"),
+ vec!("id",
+ "refid",
+ "refidcrate",
+ "traitid",
+ "traitidcrate",
+ "scopeid"),
true,
true),
- Module => ("module", vec!("id","qualname","scopeid","def_file"), true, false),
- UseAlias => ("use_alias", vec!("id","refid","refidcrate","name","scopeid"), true, true),
- UseGlob => ("use_glob", vec!("id","value","scopeid"), true, true),
+ Module => ("module",
+ vec!("id", "qualname", "scopeid", "def_file"),
+ true,
+ false),
+ UseAlias => ("use_alias",
+ vec!("id", "refid", "refidcrate", "name", "scopeid"),
+ true,
+ true),
+ UseGlob => ("use_glob", vec!("id", "value", "scopeid"), true, true),
ExternCrate => ("extern_crate",
- vec!("id","name","location","crate","scopeid"),
+ vec!("id", "name", "location", "crate", "scopeid"),
true,
true),
Inheritance => ("inheritance",
- vec!("base","basecrate","derived","derivedcrate"),
+ vec!("base", "basecrate", "derived", "derivedcrate"),
true,
false),
MethodCall => ("method_call",
- vec!("refid","refidcrate","declid","declidcrate","scopeid"),
+ vec!("refid", "refidcrate", "declid", "declidcrate", "scopeid"),
true,
true),
- Typedef => ("typedef", vec!("id","qualname","value"), true, true),
- ExternalCrate => ("external_crate", vec!("name","crate","file_name"), false, false),
+ Typedef => ("typedef", vec!("id", "qualname", "value"), true, true),
+ ExternalCrate => ("external_crate",
+ vec!("name", "crate", "file_name"),
+ false,
+ false),
Crate => ("crate", vec!("name"), true, false),
- FnCall => ("fn_call", vec!("refid","refidcrate","qualname","scopeid"), true, true),
- ModRef => ("mod_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true),
- VarRef => ("var_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true),
- TypeRef => ("type_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true),
- FnRef => ("fn_ref", vec!("refid","refidcrate","qualname","scopeid"), true, true),
+ FnCall => ("fn_call",
+ vec!("refid", "refidcrate", "qualname", "scopeid"),
+ true,
+ true),
+ ModRef => ("mod_ref",
+ vec!("refid", "refidcrate", "qualname", "scopeid"),
+ true,
+ true),
+ VarRef => ("var_ref",
+ vec!("refid", "refidcrate", "qualname", "scopeid"),
+ true,
+ true),
+ TypeRef => ("type_ref",
+ vec!("refid", "refidcrate", "qualname", "scopeid"),
+ true,
+ true),
+ FnRef => ("fn_ref",
+ vec!("refid", "refidcrate", "qualname", "scopeid"),
+ true,
+ true),
}
}
span: Span)
-> Option<String> {
if values.len() != fields.len() {
- self.span.sess.span_bug(span, &format!(
- "Mismatch between length of fields for '{}', expected '{}', found '{}'",
- kind, fields.len(), values.len()));
+ self.span.sess.span_bug(span,
+ &format!("Mismatch between length of fields for '{}', \
+ expected '{}', found '{}'",
+ kind,
+ fields.len(),
+ values.len()));
}
let values = values.iter().map(|s| {
let pairs = fields.iter().zip(values);
let strs = pairs.map(|(f, v)| format!(",{},\"{}\"", f, escape(String::from(v))));
- Some(strs.fold(String::new(), |mut s, ss| {
- s.push_str(&ss[..]);
- s
- }))
+ Some(strs.fold(String::new(),
+ |mut s, ss| {
+ s.push_str(&ss[..]);
+ s
+ }))
}
pub fn record_without_span(&mut self, kind: Row, values: Vec<String>, span: Span) {
let (label, ref fields, needs_span, dump_spans) = FmtStrs::lookup_row(kind);
if needs_span {
- self.span.sess.span_bug(span, &format!(
- "Called record_without_span for '{}' which does requires a span",
- label));
+ self.span.sess.span_bug(span,
+ &format!("Called record_without_span for '{}' which does \
+ requires a span",
+ label));
}
assert!(!dump_spans);
if self.recorder.dump_spans {
if dump_spans {
- self.recorder.dump_span(self.span.clone(),
- label,
- span,
- Some(sub_span));
+ self.recorder.dump_span(self.span.clone(), label, span, Some(sub_span));
}
return;
}
if !needs_span {
self.span.sess.span_bug(span,
- &format!("Called record_with_span for '{}' \
- which does not require a span", label));
+ &format!("Called record_with_span for '{}' which does not \
+ require a span",
+ label));
}
let values_str = match self.make_values_str(label, fields, values, span) {
Some(vs) => vs,
None => return,
};
- let result = format!("{},{}{}\n", label, self.span.extent_str(sub_span), values_str);
+ let result = format!("{},{}{}\n",
+ label,
+ self.span.extent_str(sub_span),
+ values_str);
self.recorder.record(&result[..]);
}
let mut qualname = String::from(name);
qualname.push_str("$");
qualname.push_str(&id.to_string());
+ let id = self.normalize_node_id(id);
self.check_and_record(Variable,
span,
sub_span,
let mut qualname = String::from(fn_name);
qualname.push_str("::");
qualname.push_str(name);
+ let id = self.normalize_node_id(id);
self.check_and_record(Variable,
span,
sub_span,
value: &str,
typ: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Variable,
span,
sub_span,
qualname: &str,
typ: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Variable,
span,
sub_span,
name: &str,
scope_id: NodeId,
value: &str) {
- self.check_and_record(Enum,
- span,
- sub_span,
- svec!(id, name, scope_id, value));
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ self.check_and_record(Enum, span, sub_span, svec!(id, name, scope_id, value));
}
pub fn tuple_variant_str(&mut self,
typ: &str,
val: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Variant,
span,
sub_span,
typ: &str,
val: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ let ctor_id = self.normalize_node_id(ctor_id);
self.check_and_record(VariantStruct,
span,
sub_span,
id: NodeId,
name: &str,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(Function,
span,
sub_span,
name: &str,
decl_id: Option<DefId>,
scope_id: NodeId) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
let values = match decl_id {
- Some(decl_id) => svec!(id, name, decl_id.node, decl_id.krate, scope_id),
+ Some(decl_id) => svec!(id,
+ name,
+ decl_id.index.as_usize(),
+ decl_id.krate,
+ scope_id),
None => svec!(id, name, "", "", scope_id),
};
- self.check_and_record(Function,
- span,
- sub_span,
- values);
+ self.check_and_record(Function, span, sub_span, values);
}
pub fn method_decl_str(&mut self,
id: NodeId,
name: &str,
scope_id: NodeId) {
- self.check_and_record(MethodDecl,
- span,
- sub_span,
- svec!(id, name, scope_id));
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ self.check_and_record(MethodDecl, span, sub_span, svec!(id, name, scope_id));
}
pub fn struct_str(&mut self,
name: &str,
scope_id: NodeId,
value: &str) {
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ let ctor_id = self.normalize_node_id(ctor_id);
self.check_and_record(Struct,
span,
sub_span,
name: &str,
scope_id: NodeId,
value: &str) {
- self.check_and_record(Trait,
- span,
- sub_span,
- svec!(id, name, scope_id, value));
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ self.check_and_record(Trait, span, sub_span, svec!(id, name, scope_id, value));
}
pub fn impl_str(&mut self,
ref_id: Option<DefId>,
trait_id: Option<DefId>,
scope_id: NodeId) {
- let ref_id = ref_id.unwrap_or(ZERO_DEF_ID);
- let trait_id = trait_id.unwrap_or(ZERO_DEF_ID);
+ let id = self.normalize_node_id(id);
+ let scope_id = self.normalize_node_id(scope_id);
+ let ref_id = ref_id.unwrap_or(CRATE_ROOT_DEF_ID);
+ let trait_id = trait_id.unwrap_or(CRATE_ROOT_DEF_ID);
self.check_and_record(Impl,
span,
sub_span,
svec!(id,
- ref_id.node,
+ ref_id.index.as_usize(),
ref_id.krate,
- trait_id.node,
+ trait_id.index.as_usize(),
trait_id.krate,
scope_id));
}
name: &str,
parent: NodeId,
filename: &str) {
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
self.check_and_record(Module,
span,
sub_span,
mod_id: Option<DefId>,
name: &str,
parent: NodeId) {
- let (mod_node, mod_crate) = match mod_id {
- Some(mod_id) => (mod_id.node, mod_id.krate),
- None => (0, 0),
- };
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
+ let mod_id = mod_id.unwrap_or(CRATE_ROOT_DEF_ID);
self.check_and_record(UseAlias,
span,
sub_span,
- svec!(id, mod_node, mod_crate, name, parent));
+ svec!(id, mod_id.index.as_usize(), mod_id.krate, name, parent));
}
pub fn use_glob_str(&mut self,
id: NodeId,
values: &str,
parent: NodeId) {
- self.check_and_record(UseGlob,
- span,
- sub_span,
- svec!(id, values, parent));
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
+ self.check_and_record(UseGlob, span, sub_span, svec!(id, values, parent));
}
pub fn extern_crate_str(&mut self,
name: &str,
loc: &str,
parent: NodeId) {
+ let id = self.normalize_node_id(id);
+ let parent = self.normalize_node_id(parent);
self.check_and_record(ExternCrate,
span,
sub_span,
sub_span: Option<Span>,
base_id: DefId,
deriv_id: NodeId) {
+ let deriv_id = self.normalize_node_id(deriv_id);
self.check_and_record(Inheritance,
span,
sub_span,
- svec!(base_id.node,
- base_id.krate,
- deriv_id,
- 0));
+ svec!(base_id.index.as_usize(), base_id.krate, deriv_id, 0));
}
pub fn fn_call_str(&mut self,
sub_span: Option<Span>,
id: DefId,
scope_id: NodeId) {
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(FnCall,
span,
sub_span,
- svec!(id.node, id.krate, "", scope_id));
+ svec!(id.index.as_usize(), id.krate, "", scope_id));
}
pub fn meth_call_str(&mut self,
defid: Option<DefId>,
declid: Option<DefId>,
scope_id: NodeId) {
- let (dfn, dfk) = match defid {
- Some(defid) => (defid.node, defid.krate),
- None => (0, 0),
- };
+ let scope_id = self.normalize_node_id(scope_id);
+ let defid = defid.unwrap_or(CRATE_ROOT_DEF_ID);
let (dcn, dck) = match declid {
- Some(declid) => (s!(declid.node), s!(declid.krate)),
+ Some(declid) => (s!(declid.index.as_usize()), s!(declid.krate)),
None => ("".to_string(), "".to_string()),
};
self.check_and_record(MethodCall,
span,
sub_span,
- svec!(dfn, dfk, dcn, dck, scope_id));
+ svec!(defid.index.as_usize(), defid.krate, dcn, dck, scope_id));
}
pub fn sub_mod_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str, parent: NodeId) {
- self.record_with_span(ModRef,
- span,
- sub_span,
- svec!(0, 0, qualname, parent));
+ let parent = self.normalize_node_id(parent);
+ self.record_with_span(ModRef, span, sub_span, svec!(0, 0, qualname, parent));
}
pub fn typedef_str(&mut self,
id: NodeId,
qualname: &str,
value: &str) {
- self.check_and_record(Typedef,
- span,
- sub_span,
- svec!(id, qualname, value));
+ let id = self.normalize_node_id(id);
+ self.check_and_record(Typedef, span, sub_span, svec!(id, qualname, value));
}
pub fn crate_str(&mut self, span: Span, name: &str) {
- self.record_with_span(Crate,
- span,
- span,
- svec!(name));
+ self.record_with_span(Crate, span, span, svec!(name));
}
pub fn external_crate_str(&mut self, span: Span, name: &str, num: ast::CrateNum) {
}
pub fn sub_type_ref_str(&mut self, span: Span, sub_span: Span, qualname: &str) {
- self.record_with_span(TypeRef,
- span,
- sub_span,
- svec!(0, 0, qualname, 0));
+ self.record_with_span(TypeRef, span, sub_span, svec!(0, 0, qualname, 0));
}
// A slightly generic function for a reference to an item of any kind.
sub_span: Option<Span>,
id: DefId,
scope_id: NodeId) {
+ let scope_id = self.normalize_node_id(scope_id);
self.check_and_record(kind,
span,
sub_span,
- svec!(id.node, id.krate, "", scope_id));
+ svec!(id.index.as_usize(), id.krate, "", scope_id));
}
}
impl<'a> SpanUtils<'a> {
pub fn new(sess: &'a Session) -> SpanUtils<'a> {
- SpanUtils { sess: sess, err_count: Cell::new(0) }
+ SpanUtils {
+ sess: sess,
+ err_count: Cell::new(0),
+ }
}
// Standard string for extents/location.
+ #[rustfmt_skip]
pub fn extent_str(&self, span: Span) -> String {
let lo_loc = self.sess.codemap().lookup_char_pos(span.lo);
let hi_loc = self.sess.codemap().lookup_char_pos(span.hi);
let loc = self.sess.codemap().lookup_char_pos(span.lo);
assert!(!generated_code(span),
"generated code; we should not be processing this `{}` in {}, line {}",
- self.snippet(span), loc.file.name, loc.line);
+ self.snippet(span),
+ loc.file.name,
+ loc.line);
match sub_span {
None => None,
// the codemap as a new filemap. This is mostly OK, but means we should
// not iterate over the codemap. Also, any spans over the new filemap
// are incompatible with spans over other filemaps.
- let filemap = self.sess.codemap().new_filemap(String::from("<anon-dxr>"),
- self.snippet(span));
+ let filemap = self.sess
+ .codemap()
+ .new_filemap(String::from("<anon-dxr>"), self.snippet(span));
let s = self.sess;
lexer::StringReader::new(s.diagnostic(), filemap)
}
if bracket_count != 0 {
let loc = self.sess.codemap().lookup_char_pos(span.lo);
self.sess.span_bug(span,
- &format!("Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
- self.snippet(span), loc.file.name, loc.line));
+ &format!("Mis-counted brackets when breaking path? Parsing '{}' \
+ in {}, line {}",
+ self.snippet(span),
+ loc.file.name,
+ loc.line));
}
if result.is_none() && prev.tok.is_ident() && bracket_count == 0 {
return self.make_sub_span(span, Some(prev.sp));
if ts.tok == token::Eof {
if bracket_count != 0 {
let loc = self.sess.codemap().lookup_char_pos(span.lo);
- self.sess.span_bug(span, &format!(
- "Mis-counted brackets when breaking path? Parsing '{}' in {}, line {}",
- self.snippet(span), loc.file.name, loc.line));
+ self.sess.span_bug(span,
+ &format!("Mis-counted brackets when breaking path? \
+ Parsing '{}' in {}, line {}",
+ self.snippet(span),
+ loc.file.name,
+ loc.line));
}
return result
}
pub fn report_span_err(&self, kind: &str, span: Span) {
let loc = self.sess.codemap().lookup_char_pos(span.lo);
info!("({}) Could not find sub_span in `{}` in {}, line {}",
- kind, self.snippet(span), loc.file.name, loc.line);
- self.err_count.set(self.err_count.get()+1);
+ kind,
+ self.snippet(span),
+ loc.file.name,
+ loc.line);
+ self.err_count.set(self.err_count.get() + 1);
if self.err_count.get() > 1000 {
self.sess.bug("span errors reached 1000, giving up");
}
use std::rc::Rc;
use rustc_front::hir;
use syntax::ast::{self, DUMMY_NODE_ID, NodeId};
+use syntax::ext::mtwt;
use syntax::codemap::Span;
use rustc_front::fold::Folder;
use syntax::ptr::P;
}
fn trans<'blk>(&self, mut bcx: Block<'blk, 'tcx>) -> OptResult<'blk, 'tcx> {
+ use trans::consts::TrueConst::Yes;
let _icx = push_ctxt("match::trans_opt");
let ccx = bcx.ccx();
match *self {
ConstantValue(ConstantExpr(lit_expr), _) => {
let lit_ty = bcx.tcx().node_id_to_type(lit_expr.id);
- let (llval, _) = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None);
+ let expr = consts::const_expr(ccx, &*lit_expr, bcx.fcx.param_substs, None, Yes);
+ let llval = match expr {
+ Ok((llval, _)) => llval,
+ Err(err) => bcx.ccx().sess().span_fatal(lit_expr.span, &err.description()),
+ };
let lit_datum = immediate_rvalue(llval, lit_ty);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
SingleResult(Result::new(bcx, lit_datum.val))
}
ConstantRange(ConstantExpr(ref l1), ConstantExpr(ref l2), _) => {
- let (l1, _) = consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None);
- let (l2, _) = consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None);
+ let l1 = match consts::const_expr(ccx, &**l1, bcx.fcx.param_substs, None, Yes) {
+ Ok((l1, _)) => l1,
+ Err(err) => bcx.ccx().sess().span_fatal(l1.span, &err.description()),
+ };
+ let l2 = match consts::const_expr(ccx, &**l2, bcx.fcx.param_substs, None, Yes) {
+ Ok((l2, _)) => l2,
+ Err(err) => bcx.ccx().sess().span_fatal(l2.span, &err.description()),
+ };
RangeResult(Result::new(bcx, l1), Result::new(bcx, l2))
}
Variant(disr_val, ref repr, _, _) => {
pub ty: Ty<'tcx>,
}
-type BindingsMap<'tcx> = FnvHashMap<ast::Ident, BindingInfo<'tcx>>;
+type BindingsMap<'tcx> = FnvHashMap<ast::Name, BindingInfo<'tcx>>;
struct ArmData<'p, 'blk, 'tcx: 'blk> {
bodycx: Block<'blk, 'tcx>,
struct Match<'a, 'p: 'a, 'blk: 'a, 'tcx: 'blk> {
pats: Vec<&'p hir::Pat>,
data: &'a ArmData<'p, 'blk, 'tcx>,
- bound_ptrs: Vec<(ast::Ident, ValueRef)>,
+ bound_ptrs: Vec<(ast::Name, ValueRef)>,
// Thread along renamings done by the check_match::StaticInliner, so we can
// map back to original NodeIds
pat_renaming_map: Option<&'a FnvHashMap<(NodeId, Span), NodeId>>
loop {
pat = match pat.node {
hir::PatIdent(_, ref path, Some(ref inner)) => {
- bound_ptrs.push((path.node, val.val));
+ bound_ptrs.push((mtwt::resolve(path.node), val.val));
&**inner
},
_ => break
match this.node {
hir::PatIdent(_, ref path, None) => {
if pat_is_binding(dm, &*this) {
- bound_ptrs.push((path.node, val.val));
+ bound_ptrs.push((mtwt::resolve(path.node), val.val));
}
}
hir::PatVec(ref before, Some(ref slice), ref after) => {
let subslice_val = bind_subslice_pat(
bcx, this.id, val,
before.len(), after.len());
- bound_ptrs.push((path.node, subslice_val));
+ bound_ptrs.push((mtwt::resolve(path.node), subslice_val));
}
}
_ => {}
compare_str(cx, lhs_data, lhs_len, rhs_data, rhs_len, rhs_t, debug_loc)
}
ty::TyArray(ty, _) | ty::TySlice(ty) => match ty.sty {
- ty::TyUint(hir::TyU8) => {
+ ty::TyUint(ast::TyU8) => {
// NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item,
// which calls memcmp().
let pat_len = val_ty(rhs).element_type().array_length();
bindings_map: &BindingsMap<'tcx>,
cs: Option<cleanup::ScopeId>)
-> Block<'blk, 'tcx> {
- for (&ident, &binding_info) in bindings_map {
+ for (&name, &binding_info) in bindings_map {
let (llval, aliases_other_state) = match binding_info.trmode {
// By value mut binding for a copy type: load from the ptr
// into the matched value and copy to our alloca
// leaving the remainder of the tuple `(_,
// D(B))` still to be dropped in the future.
//
- // Thus, here we must must zero the place that
- // we are moving *from*, because we do not yet
+ // Thus, here we must zero the place that we
+ // are moving *from*, because we do not yet
// track drop flags for a fragmented parent
// match input expression.
//
debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval));
bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum);
- debuginfo::create_match_binding_metadata(bcx, ident.name, binding_info);
+ debuginfo::create_match_binding_metadata(bcx, name, binding_info);
}
bcx
}
}
None => {
let data = &m[0].data;
- for &(ref ident, ref value_ptr) in &m[0].bound_ptrs {
- let binfo = *data.bindings_map.get(ident).unwrap();
+ for &(ref name, ref value_ptr) in &m[0].bound_ptrs {
+ let binfo = *data.bindings_map.get(name).unwrap();
call_lifetime_start(bcx, binfo.llmatch);
if binfo.trmode == TrByRef && type_is_fat_ptr(bcx.tcx(), binfo.ty) {
expr::copy_fat_ptr(bcx, *value_ptr, binfo.llmatch);
let exhaustive = chk.is_infallible() && defaults.is_empty();
let len = opts.len();
+ if exhaustive && kind == Switch {
+ build::Unreachable(else_cx);
+ }
+
// Compile subtrees for each option
for (i, opt) in opts.iter().enumerate() {
// In some cases of range and vector pattern matching, we need to
let mut opt_cx = else_cx;
let debug_loc = opt.debug_loc();
- if !exhaustive || i + 1 < len {
+ if kind == Switch || !exhaustive || i + 1 < len {
opt_cx = bcx.fcx.new_temp_block("match_case");
match kind {
Single => Br(bcx, opt_cx.llbb, debug_loc),
fn is_discr_reassigned(bcx: Block, discr: &hir::Expr, body: &hir::Expr) -> bool {
let (vid, field) = match discr.node {
hir::ExprPath(..) => match bcx.def(discr.id) {
- def::DefLocal(vid) | def::DefUpvar(vid, _, _) => (vid, None),
+ def::DefLocal(_, vid) | def::DefUpvar(_, vid, _, _) => (vid, None),
_ => return false
},
hir::ExprField(ref base, field) => {
let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
- Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _, _)) => vid,
+ Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
_ => return false
};
- (vid, Some(mc::NamedField(field.node.name)))
+ (vid, Some(mc::NamedField(field.node)))
},
hir::ExprTupField(ref base, field) => {
let vid = match bcx.tcx().def_map.borrow().get(&base.id).map(|d| d.full_def()) {
- Some(def::DefLocal(vid)) | Some(def::DefUpvar(vid, _, _)) => vid,
+ Some(def::DefLocal(_, vid)) | Some(def::DefUpvar(_, vid, _, _)) => vid,
_ => return false
};
(vid, Some(mc::PositionalField(field.node)))
let tcx = bcx.tcx();
let reassigned = is_discr_reassigned(bcx, discr, body);
let mut bindings_map = FnvHashMap();
- pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path1| {
- let ident = path1.node;
- let name = ident.name;
+ pat_bindings_hygienic(&tcx.def_map, &*pat, |bm, p_id, span, path1| {
+ let name = mtwt::resolve(path1.node);
let variable_ty = node_id_type(bcx, p_id);
let llvariable_ty = type_of::type_of(ccx, variable_ty);
let tcx = bcx.tcx();
trmode = TrByRef;
}
};
- bindings_map.insert(ident, BindingInfo {
+ bindings_map.insert(name, BindingInfo {
llmatch: llmatch,
trmode: trmode,
id: p_id,
pat_bindings(&tcx.def_map, pat, |_, p_id, _, path1| {
let scope = cleanup::var_scope(tcx, p_id);
bcx = mk_binding_alloca(
- bcx, p_id, path1.node.name, scope, (),
+ bcx, p_id, path1.node, scope, (),
"_match::store_local::create_dummy_locals",
|(), bcx, Datum { val: llval, ty, kind }| {
// Dummy-locals start out uninitialized, so set their
//
// In such cases, the more general path is unsafe, because
// it assumes it is matching against a valid value.
- match simple_identifier(&*pat) {
- Some(ident) => {
+ match simple_name(pat) {
+ Some(name) => {
let var_scope = cleanup::var_scope(tcx, local.id);
return mk_binding_alloca(
- bcx, pat.id, ident.name, var_scope, (),
+ bcx, pat.id, name, var_scope, (),
"_match::store_local",
|(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &**init_expr,
expr::SaveIn(v)));
let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
let pat_v = VariantInfo::of_node(tcx, pat_ty, pat.id);
for f in fields {
- let name = f.node.ident.name;
+ let name = f.node.name;
let fldptr = adt::trans_field_ptr(
bcx,
&*pat_repr,
use middle::ty::{self, Ty};
use middle::ty::Disr;
use syntax::ast;
-use rustc_front::attr;
-use rustc_front::attr::IntType;
-use rustc_front::hir;
+use syntax::attr;
+use syntax::attr::IntType;
use trans::_match;
use trans::build::*;
use trans::cleanup;
let ity = if use_align {
// Use the overall alignment
match align {
- 1 => attr::UnsignedInt(hir::TyU8),
- 2 => attr::UnsignedInt(hir::TyU16),
- 4 => attr::UnsignedInt(hir::TyU32),
+ 1 => attr::UnsignedInt(ast::TyU8),
+ 2 => attr::UnsignedInt(ast::TyU16),
+ 4 => attr::UnsignedInt(ast::TyU32),
8 if machine::llalign_of_min(cx, Type::i64(cx)) == 8 =>
- attr::UnsignedInt(hir::TyU64),
+ attr::UnsignedInt(ast::TyU64),
_ => min_ity // use min_ity as a fallback
}
} else {
// Lists of sizes to try. u64 is always allowed as a fallback.
#[allow(non_upper_case_globals)]
const choose_shortest: &'static [IntType] = &[
- attr::UnsignedInt(hir::TyU8), attr::SignedInt(hir::TyI8),
- attr::UnsignedInt(hir::TyU16), attr::SignedInt(hir::TyI16),
- attr::UnsignedInt(hir::TyU32), attr::SignedInt(hir::TyI32)];
+ attr::UnsignedInt(ast::TyU8), attr::SignedInt(ast::TyI8),
+ attr::UnsignedInt(ast::TyU16), attr::SignedInt(ast::TyI16),
+ attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)];
#[allow(non_upper_case_globals)]
const at_least_32: &'static [IntType] = &[
- attr::UnsignedInt(hir::TyU32), attr::SignedInt(hir::TyI32)];
+ attr::UnsignedInt(ast::TyU32), attr::SignedInt(ast::TyI32)];
let attempts;
match hint {
return ity;
}
}
- return attr::UnsignedInt(hir::TyU64);
+ return attr::UnsignedInt(ast::TyU64);
}
pub fn ll_inttype(cx: &CrateContext, ity: IntType) -> Type {
use rustc_front::hir as ast;
use std::ffi::CString;
+use syntax::ast::AsmDialect;
use libc::{c_uint, c_char};
// Take an inline assembly expression and splat it out via LLVM
};
let dialect = match ia.dialect {
- ast::AsmAtt => llvm::AD_ATT,
- ast::AsmIntel => llvm::AD_Intel
+ AsmDialect::Att => llvm::AD_ATT,
+ AsmDialect::Intel => llvm::AD_Intel
};
let asm = CString::new(ia.asm.as_bytes()).unwrap();
use middle::infer;
use session::config::NoDebugInfo;
use syntax::abi;
+pub use syntax::attr::InlineAttr;
+use syntax::ast;
use rustc_front::hir;
-pub use rustc_front::attr::InlineAttr;
use trans::base;
use trans::common;
use trans::context::CrateContext;
/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute])
/// attributes.
-pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[hir::Attribute], llfn: ValueRef) {
- use rustc_front::attr::*;
+pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) {
+ use syntax::attr::*;
inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs));
// FIXME: #11906: Omitting frame pointers breaks retrieving the value of a
use metadata::{csearch, encoder, loader};
use middle::astencode;
use middle::cfg;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
use middle::weak_lang_items;
-use middle::pat_util::simple_identifier;
+use middle::pat_util::simple_name;
use middle::subst::Substs;
use middle::ty::{self, Ty, HasTypeFlags};
use rustc::front::map as hir_map;
use std::ffi::{CStr, CString};
use std::cell::{Cell, RefCell};
use std::collections::{HashMap, HashSet};
-use std::mem;
use std::str;
use std::{i8, i16, i32, i64};
use syntax::abi::{Rust, RustCall, RustIntrinsic, PlatformIntrinsic, Abi};
use syntax::codemap::Span;
use syntax::parse::token::InternedString;
+use syntax::attr::AttrMetaMethods;
+use syntax::attr;
use rustc_front;
-use rustc_front::attr::AttrMetaMethods;
-use rustc_front::attr;
use rustc_front::visit::Visitor;
use rustc_front::visit;
use rustc_front::hir;
ty::TyInt(t) => {
let llty = Type::int_from_ty(cx.ccx(), t);
let min = match t {
- hir::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
- hir::TyIs => i64::MIN as u64,
- hir::TyI8 => i8::MIN as u64,
- hir::TyI16 => i16::MIN as u64,
- hir::TyI32 => i32::MIN as u64,
- hir::TyI64 => i64::MIN as u64,
+ ast::TyIs if llty == Type::i32(cx.ccx()) => i32::MIN as u64,
+ ast::TyIs => i64::MIN as u64,
+ ast::TyI8 => i8::MIN as u64,
+ ast::TyI16 => i16::MIN as u64,
+ ast::TyI32 => i32::MIN as u64,
+ ast::TyI64 => i64::MIN as u64,
};
(llty, min)
}
}
Some(hir_map::NodeBlock(blk)) if blk.id == blk_id => {
let mut visitor = FindNestedReturn::new();
- visit::walk_expr_opt(&mut visitor, &blk.expr);
+ walk_list!(&mut visitor, visit_expr, &blk.expr);
if visitor.found {
return true;
}
// Create the drop-flag hints for every unfragmented path in the function.
let tcx = fcx.ccx.tcx();
- let fn_did = DefId { krate: LOCAL_CRATE, node: fcx.id };
+ let fn_did = tcx.map.local_def_id(fcx.id);
let mut hints = fcx.lldropflag_hints.borrow_mut();
let fragment_infos = tcx.fragment_infos.borrow();
};
let pat = &*args[i].pat;
- bcx = if let Some(ident) = simple_identifier(&*pat) {
+ bcx = if let Some(name) = simple_name(pat) {
// Generate nicer LLVM for the common case of fn a pattern
// like `x: T`
- set_value_name(arg_datum.val, &bcx.name(ident.name));
+ set_value_name(arg_datum.val, &bcx.name(name));
bcx.fcx.lllocals.borrow_mut().insert(pat.id, arg_datum);
bcx
} else {
llfndecl: ValueRef,
param_substs: &'tcx Substs<'tcx>,
fn_ast_id: ast::NodeId,
- _attributes: &[hir::Attribute],
+ _attributes: &[ast::Attribute],
output_type: ty::FnOutput<'tcx>,
abi: Abi,
closure_env: closure::ClosureEnv<'b>) {
param_substs);
let has_env = match closure_env {
- closure::ClosureEnv::Closure(_) => true,
+ closure::ClosureEnv::Closure(..) => true,
closure::ClosureEnv::NotClosure => false,
};
llfndecl: ValueRef,
param_substs: &'tcx Substs<'tcx>,
id: ast::NodeId,
- attrs: &[hir::Attribute]) {
+ attrs: &[ast::Attribute]) {
let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string());
debug!("trans_fn(param_substs={:?})", param_substs);
let _icx = push_ctxt("trans_fn");
// error in trans. This is used to write compile-fail tests
// that actually test that compilation succeeds without
// reporting an error.
- if ccx.tcx().has_attr(DefId::local(item.id), "rustc_error") {
+ let item_def_id = ccx.tcx().map.local_def_id(item.id);
+ if ccx.tcx().has_attr(item_def_id, "rustc_error") {
ccx.tcx().sess.span_fatal(item.span, "compilation successful");
}
}
}
hir::ItemImpl(_, _, ref generics, _, _, ref impl_items) => {
meth::trans_impl(ccx,
- item.ident,
+ item.name,
&impl_items[..],
generics,
item.id);
let mut v = TransItemVisitor{ ccx: ccx };
v.visit_expr(&**expr);
- let g = consts::trans_static(ccx, m, expr, item.id, &item.attrs);
+ let g = match consts::trans_static(ccx, m, expr, item.id, &item.attrs) {
+ Ok(g) => g,
+ Err(err) => ccx.tcx().sess.span_fatal(expr.span, &err.description()),
+ };
set_global_section(ccx, g, item);
update_linkage(ccx, g, Some(item.id), OriginalTranslation);
},
Ok(id) => id,
Err(s) => { ccx.sess().fatal(&s[..]); }
};
- let start_fn = if start_def_id.is_local() {
- get_item_val(ccx, start_def_id.node)
- } else {
- let start_fn_type = csearch::get_type(ccx.tcx(),
- start_def_id).ty;
- trans_external_path(ccx, start_def_id, start_fn_type)
- };
+ let start_fn =
+ if let Some(start_node_id) = ccx.tcx().map.as_local_node_id(start_def_id) {
+ get_item_val(ccx, start_node_id)
+ } else {
+ let start_fn_type = csearch::get_type(ccx.tcx(),
+ start_def_id).ty;
+ trans_external_path(ccx, start_def_id, start_fn_type)
+ };
let args = {
let opaque_rust_main = llvm::LLVMBuildPointerCast(bld,
}
fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId,
- ty: Ty<'tcx>, attrs: &[hir::Attribute]) -> String {
+ ty: Ty<'tcx>, attrs: &[ast::Attribute]) -> String {
match ccx.external_srcs().borrow().get(&id) {
Some(&did) => {
let sym = csearch::get_symbol(&ccx.sess().cstore, did);
match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) {
// Use provided name
Some(name) => name.to_string(),
- _ => ccx.tcx().map.with_path(id, |path| {
+ _ => {
+ let path = ccx.tcx().map.def_path_from_id(id);
if attr::contains_name(attrs, "no_mangle") {
// Don't mangle
- path.last().unwrap().to_string()
+ path.last().unwrap().data.to_string()
} else {
match weak_lang_items::link_name(attrs) {
Some(name) => name.to_string(),
}
}
}
- })
+ }
}
}
hir_map::NodeVariant(ref v) => {
let llfn;
- let args = match v.node.kind {
- hir::TupleVariantKind(ref args) => args,
- hir::StructVariantKind(_) => {
- ccx.sess().bug("struct variant kind unexpected in get_item_val")
- }
+ let fields = if v.node.data.is_struct() {
+ ccx.sess().bug("struct variant kind unexpected in get_item_val")
+ } else {
+ v.node.data.fields()
};
- assert!(!args.is_empty());
+ assert!(!fields.is_empty());
let ty = ccx.tcx().node_id_to_type(id);
let parent = ccx.tcx().map.get_parent(id);
let enm = ccx.tcx().map.expect_item(parent);
hir_map::NodeStructCtor(struct_def) => {
// Only register the constructor if this is a tuple-like struct.
- let ctor_id = match struct_def.ctor_id {
- None => {
- ccx.sess().bug("attempt to register a constructor of \
- a non-tuple-like struct")
- }
- Some(ctor_id) => ctor_id,
+ let ctor_id = if struct_def.is_struct() {
+ ccx.sess().bug("attempt to register a constructor of \
+ a non-tuple-like struct")
+ } else {
+ struct_def.id()
};
let parent = ccx.tcx().map.get_parent(id);
let struct_item = ccx.tcx().map.expect_item(parent);
}
fn register_method(ccx: &CrateContext, id: ast::NodeId,
- attrs: &[hir::Attribute], span: Span) -> ValueRef {
+ attrs: &[ast::Attribute], span: Span) -> ValueRef {
let mty = ccx.tcx().node_id_to_type(id);
let sym = exported_name(ccx, id, mty, &attrs);
fn next(&mut self) -> Option<ValueRef> {
let old = self.cur;
if !old.is_null() {
- self.cur = unsafe {
- let step: unsafe extern "C" fn(ValueRef) -> ValueRef =
- mem::transmute_copy(&self.step);
- step(old)
- };
+ self.cur = unsafe { (self.step)(old) };
Some(old)
} else {
None
}
}
- let mut arg_tys = Vec::new();
- for t in atys {
- let ty = x86_64_ty(ccx, *t, |cls| cls.is_pass_byval(), Attribute::ByVal);
- arg_tys.push(ty);
- }
+ let mut int_regs = 6; // RDI, RSI, RDX, RCX, R8, R9
+ let mut sse_regs = 8; // XMM0-7
let ret_ty = if ret_def {
- x86_64_ty(ccx, rty, |cls| cls.is_ret_bysret(), Attribute::StructRet)
+ x86_64_ty(ccx, rty, |cls| {
+ if cls.is_ret_bysret() {
+ // `sret` parameter thus one less register available
+ int_regs -= 1;
+ true
+ } else {
+ false
+ }
+ }, Attribute::StructRet)
} else {
ArgType::direct(Type::void(ccx), None, None, None)
};
+ let mut arg_tys = Vec::new();
+ for t in atys {
+ let ty = x86_64_ty(ccx, *t, |cls| {
+ let needed_int = cls.iter().filter(|&&c| c == Int).count() as isize;
+ let needed_sse = cls.iter().filter(|c| c.is_sse()).count() as isize;
+ let in_mem = cls.is_pass_byval() ||
+ int_regs < needed_int ||
+ sse_regs < needed_sse;
+ if in_mem {
+ // `byval` parameter thus one less integer register available
+ int_regs -= 1;
+ } else {
+ // split into sized chunks passed individually
+ int_regs -= needed_int;
+ sse_regs -= needed_sse;
+ }
+ in_mem
+ }, Attribute::ByVal);
+ arg_tys.push(ty);
+
+ // An integer, pointer, double or float parameter
+ // thus the above closure passed to `x86_64_ty` won't
+ // get called.
+ if t.kind() == Integer || t.kind() == Pointer {
+ int_regs -= 1;
+ } else if t.kind() == Double || t.kind() == Float {
+ sse_regs -= 1;
+ }
+ }
+
return FnType {
arg_tys: arg_tys,
ret_ty: ret_ty,
2 => ArgType::direct(t, Some(Type::i16(ccx)), None, None),
4 => ArgType::direct(t, Some(Type::i32(ccx)), None, None),
8 => ArgType::direct(t, Some(Type::i64(ccx)), None, None),
- _ => ArgType::indirect(t, Some(Attribute::ByVal))
+ _ => ArgType::indirect(t, None)
}
}
_ => {
use back::link;
use session;
use llvm::{self, ValueRef, get_params};
+use metadata::cstore::LOCAL_CRATE;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::infer::normalize_associated_type;
use middle::subst;
-use middle::subst::{Subst, Substs};
+use middle::subst::{Substs};
use rustc::front::map as hir_map;
use trans::adt;
use trans::base;
match def {
def::DefFn(did, _) if {
let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
- let maybe_ast_node = maybe_def_id.and_then(|def_id| bcx.tcx().map
- .find(def_id.node));
+ let maybe_ast_node = maybe_def_id.and_then(|def_id| {
+ let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
+ bcx.tcx().map.find(node_id)
+ });
match maybe_ast_node {
Some(hir_map::NodeStructCtor(_)) => true,
_ => false
ExprId(ref_expr.id),
bcx.fcx.param_substs);
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
- Callee { bcx: bcx, data: Intrinsic(def_id.node, substs), ty: expr_ty }
+ let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
+ Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
}
def::DefFn(did, _) => {
fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
}
def::DefMod(..) | def::DefForeignMod(..) | def::DefTrait(..) |
def::DefTy(..) | def::DefPrimTy(..) | def::DefAssociatedTy(..) |
- def::DefUse(..) | def::DefRegion(..) | def::DefLabel(..) |
- def::DefTyParam(..) | def::DefSelfTy(..) => {
+ def::DefUse(..) | def::DefLabel(..) | def::DefTyParam(..) |
+ def::DefSelfTy(..) => {
bcx.tcx().sess.span_bug(
ref_expr.span,
&format!("cannot translate def {:?} \
let llargs = get_params(fcx.llfn);
let self_idx = fcx.arg_offset();
- // the first argument (`self`) will be ptr to the the fn pointer
+ // the first argument (`self`) will be ptr to the fn pointer
let llfnpointer = if is_by_ref {
Load(bcx, llargs[self_idx])
} else {
assert!(!substs.types.has_escaping_regions());
let substs = substs.erase_regions();
- // Load the info for the appropriate trait if necessary.
- match tcx.trait_of_item(def_id) {
- None => {}
- Some(trait_id) => {
- tcx.populate_implementations_for_trait_if_necessary(trait_id)
- }
- }
-
- // We need to do a bunch of special handling for default methods.
- // We need to modify the def_id and our substs in order to monomorphize
- // the function.
- let (is_default, def_id, substs) = match tcx.provided_source(def_id) {
- None => {
- (false, def_id, tcx.mk_substs(substs))
- }
- Some(source_id) => {
- // There are two relevant substitutions when compiling
- // default methods. First, there is the substitution for
- // the type parameters of the impl we are using and the
- // method we are calling. This substitution is the substs
- // argument we already have.
- // In order to compile a default method, though, we need
- // to consider another substitution: the substitution for
- // the type parameters on trait; the impl we are using
- // implements the trait at some particular type
- // parameters, and we need to substitute for those first.
- // So, what we need to do is find this substitution and
- // compose it with the one we already have.
-
- let impl_id = tcx.impl_or_trait_item(def_id).container()
- .id();
- let impl_or_trait_item = tcx.impl_or_trait_item(source_id);
- match impl_or_trait_item {
- ty::MethodTraitItem(method) => {
- let trait_ref = tcx.impl_trait_ref(impl_id).unwrap();
-
- // Compute the first substitution
- let first_subst =
- tcx.make_substs_for_receiver_types(&trait_ref, &*method)
- .erase_regions();
-
- // And compose them
- let new_substs = tcx.mk_substs(first_subst.subst(tcx, &substs));
-
- debug!("trans_fn_with_vtables - default method: \
- substs = {:?}, trait_subst = {:?}, \
- first_subst = {:?}, new_subst = {:?}",
- substs, trait_ref.substs,
- first_subst, new_substs);
-
- (true, source_id, new_substs)
- }
- _ => {
- tcx.sess.bug("trans_fn_ref_with_vtables() tried \
- to translate a non-method?!")
- }
- }
- }
- };
-
// Check whether this fn has an inlined copy and, if so, redirect
// def_id to the local id of the inlined copy.
let def_id = inline::maybe_instantiate_inline(ccx, def_id);
- // We must monomorphise if the fn has type parameters, is a default method,
- // or is a named tuple constructor.
- let must_monomorphise = if !substs.types.is_empty() || is_default {
- true
- } else if def_id.is_local() {
+ fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool {
+ let node_id = match tcx.map.as_local_node_id(def_id) {
+ Some(n) => n,
+ None => { return false; }
+ };
let map_node = session::expect(
- ccx.sess(),
- tcx.map.find(def_id.node),
+ &tcx.sess,
+ tcx.map.find(node_id),
|| "local item should be in ast map".to_string());
match map_node {
- hir_map::NodeVariant(v) => match v.node.kind {
- hir::TupleVariantKind(ref args) => !args.is_empty(),
- _ => false
- },
+ hir_map::NodeVariant(v) => {
+ v.node.data.is_tuple()
+ }
hir_map::NodeStructCtor(_) => true,
_ => false
}
- } else {
- false
- };
+ }
+ let must_monomorphise =
+ !substs.types.is_empty() || is_named_tuple_constructor(tcx, def_id);
debug!("trans_fn_ref_with_substs({:?}) must_monomorphise: {}",
def_id, must_monomorphise);
MethodCallKey(_) => None,
};
+ let substs = tcx.mk_substs(substs);
let (val, fn_ty, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, substs, opt_ref_id);
if must_cast && node != ExprId(0) {
// Find the actual function pointer.
let mut val = {
- if def_id.is_local() {
+ if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
// Internal reference.
- get_item_val(ccx, def_id.node)
+ get_item_val(ccx, node_id)
} else {
// External reference.
trans_external_path(ccx, def_id, fn_type)
let llty = type_of::type_of_fn_from_ty(ccx, fn_type);
let llptrty = llty.ptr_to();
if common::val_ty(val) != llptrty {
- debug!("trans_fn_ref_with_vtables(): casting pointer!");
+ debug!("trans_fn_ref_with_substs(): casting pointer!");
val = consts::ptrcast(val, llptrty);
} else {
- debug!("trans_fn_ref_with_vtables(): not casting pointer!");
+ debug!("trans_fn_ref_with_substs(): not casting pointer!");
}
Datum::new(val, fn_type, Rvalue::new(ByValue))
fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ closure_def_id: DefId,
arg_scope_id: ScopeId,
freevars: &[ty::Freevar])
-> Block<'blk, 'tcx>
let _icx = push_ctxt("closure::load_closure_environment");
// Special case for small by-value selfs.
- let closure_id = DefId::local(bcx.fcx.id);
- let self_type = self_type_for_closure(bcx.ccx(), closure_id,
- node_id_type(bcx, closure_id.node));
- let kind = kind_for_closure(bcx.ccx(), closure_id);
+ let closure_ty = node_id_type(bcx, bcx.fcx.id);
+ let self_type = self_type_for_closure(bcx.ccx(), closure_def_id, closure_ty);
+ let kind = kind_for_closure(bcx.ccx(), closure_def_id);
let llenv = if kind == ty::FnOnceClosureKind &&
!arg_is_indirect(bcx.ccx(), self_type) {
let datum = rvalue_scratch_datum(bcx,
};
for (i, freevar) in freevars.iter().enumerate() {
- let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
- closure_expr_id: closure_id.node };
+ let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
+ closure_expr_id: bcx.fcx.id };
let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap();
let mut upvar_ptr = StructGEP(bcx, llenv, i);
let captured_by_ref = match upvar_capture {
true
}
};
- let def_id = freevar.def.def_id();
- bcx.fcx.llupvars.borrow_mut().insert(def_id.node, upvar_ptr);
+ let node_id = freevar.def.var_id();
+ bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr);
if kind == ty::FnOnceClosureKind && !captured_by_ref {
let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id);
bcx.fcx.schedule_drop_mem(arg_scope_id,
upvar_ptr,
- node_id_type(bcx, def_id.node),
+ node_id_type(bcx, node_id),
hint)
}
if let Some(env_pointer_alloca) = env_pointer_alloca {
debuginfo::create_captured_var_metadata(
bcx,
- def_id.node,
+ node_id,
env_pointer_alloca,
i,
captured_by_ref,
pub enum ClosureEnv<'a> {
NotClosure,
- Closure(&'a [ty::Freevar]),
+ Closure(DefId, &'a [ty::Freevar]),
}
impl<'a> ClosureEnv<'a> {
{
match self {
ClosureEnv::NotClosure => bcx,
- ClosureEnv::Closure(freevars) => {
+ ClosureEnv::Closure(def_id, freevars) => {
if freevars.is_empty() {
bcx
} else {
- load_closure_environment(bcx, arg_scope, freevars)
+ load_closure_environment(bcx, def_id, arg_scope, freevars)
}
}
}
return llfn;
}
- let symbol = ccx.tcx().map.with_path(closure_id.node, |path| {
- mangle_internal_name_by_path_and_seq(path, "closure")
- });
+ let path = ccx.tcx().def_path(closure_id);
+ let symbol = mangle_internal_name_by_path_and_seq(path, "closure");
let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs));
let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type);
decl: &hir::FnDecl,
body: &hir::Block,
id: ast::NodeId,
+ closure_def_id: DefId, // (*)
closure_substs: &'tcx ty::ClosureSubsts<'tcx>)
-> Option<Block<'a, 'tcx>>
{
+ // (*) Note that in the case of inlined functions, the `closure_def_id` will be the
+ // defid of the closure in its original crate, whereas `id` will be the id of the local
+ // inlined copy.
+
let param_substs = closure_substs.func_substs;
let ccx = match dest {
let tcx = ccx.tcx();
let _icx = push_ctxt("closure::trans_closure_expr");
- debug!("trans_closure_expr()");
+ debug!("trans_closure_expr(id={:?}, closure_def_id={:?}, closure_substs={:?})",
+ id, closure_def_id, closure_substs);
- let closure_id = DefId::local(id);
- let llfn = get_or_create_closure_declaration(ccx, closure_id, closure_substs);
+ let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
// Get the type of this closure. Use the current `param_substs` as
// the closure substitutions. This makes sense because the closure
// of the closure expression.
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables);
- let function_type = infcx.closure_type(closure_id, closure_substs);
+ let function_type = infcx.closure_type(closure_def_id, closure_substs);
let freevars: Vec<ty::Freevar> =
tcx.with_freevars(id, |fv| fv.iter().cloned().collect());
&[],
sig.output,
function_type.abi,
- ClosureEnv::Closure(&freevars));
+ ClosureEnv::Closure(closure_def_id, &freevars));
// Don't hoist this to the top of the function. It's perfectly legitimate
// to have a zero-size closure (in which case dest will be `Ignore`) and
for (i, freevar) in freevars.iter().enumerate() {
let datum = expr::trans_local_var(bcx, freevar.def);
let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i);
- let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
+ let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
closure_expr_id: id };
match tcx.upvar_capture(upvar_id).unwrap() {
ty::UpvarCapture::ByValue => {
use middle::traits;
use middle::ty::{self, HasTypeFlags, Ty};
use middle::ty::fold::{TypeFolder, TypeFoldable};
-use rustc::front::map::{PathElem, PathName};
use rustc_front::hir;
use util::nodemap::{FnvHashMap, NodeMap};
/// Generates a unique symbol based off the name given. This is used to create
/// unique symbols for things like closures.
-pub fn gensym_name(name: &str) -> PathElem {
- let num = token::gensym(name).usize();
+pub fn gensym_name(name: &str) -> ast::Name {
+ let num = token::gensym(name).0;
// use one colon which will get translated to a period by the mangler, and
// we're guaranteed that `num` is globally unique for this crate.
- PathName(token::gensym(&format!("{}:{}", name, num)))
+ token::gensym(&format!("{}:{}", name, num))
}
/*
!null_terminated as Bool);
let gsym = token::gensym("str");
- let sym = format!("str{}", gsym.usize());
+ let sym = format!("str{}", gsym.0);
let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{
cx.sess().bug(&format!("symbol `{}` is already defined", sym));
});
trait_ref);
ccx.sess().span_fatal(
span,
- "reached the recursion limit during monomorphization");
+ "reached the recursion limit during monomorphization (selection ambiguity)");
}
Err(e) => {
tcx.sess.span_bug(
}), ..}) => ty,
_ => ctor_ty
}.ty_adt_def().unwrap();
+ let inlined_vid_def_id = ccx.tcx().map.local_def_id(inlined_vid);
adt_def.variants.iter().find(|v| {
- DefId::local(inlined_vid) == v.did ||
+ inlined_vid_def_id == v.did ||
ccx.external().borrow().get(&v.did) == Some(&Some(inlined_vid))
}).unwrap_or_else(|| {
ccx.sess().bug(&format!("no variant for {:?}::{}", adt_def, inlined_vid))
use llvm;
use llvm::{ConstFCmp, ConstICmp, SetLinkage, SetUnnamedAddr};
use llvm::{InternalLinkage, ValueRef, Bool, True};
+use metadata::cstore::LOCAL_CRATE;
use middle::{check_const, def};
-use middle::const_eval::{self, ConstVal};
+use middle::const_eval::{self, ConstVal, ConstEvalErr};
use middle::const_eval::{const_int_checked_neg, const_uint_checked_neg};
use middle::const_eval::{const_int_checked_add, const_uint_checked_add};
use middle::const_eval::{const_int_checked_sub, const_uint_checked_sub};
use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
use middle::const_eval::EvalHint::ExprTypeChecked;
use middle::const_eval::eval_const_expr_partial;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
-use trans::common::*;
+use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
+use trans::common::{type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
+use trans::common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint};
+use trans::common::{type_is_fat_ptr, Field, C_vector, C_array, C_null, ExprId, MethodCallKey};
use trans::declare;
use trans::monomorphize;
use trans::type_::Type;
use util::nodemap::NodeMap;
use rustc_front::hir;
-use rustc_front::attr;
use std::ffi::{CStr, CString};
+use std::borrow::Cow;
use libc::c_uint;
use syntax::ast;
+use syntax::attr;
use syntax::parse::token;
use syntax::ptr::P;
pub type FnArgMap<'a> = Option<&'a NodeMap<ValueRef>>;
-pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &hir::Lit)
+pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit)
-> ValueRef {
let _icx = push_ctxt("trans_lit");
debug!("const_lit: {:?}", lit);
match lit.node {
- hir::LitByte(b) => C_integral(Type::uint_from_ty(cx, hir::TyU8), b as u64, false),
- hir::LitChar(i) => C_integral(Type::char(cx), i as u64, false),
- hir::LitInt(i, hir::SignedIntLit(t, _)) => {
+ ast::LitByte(b) => C_integral(Type::uint_from_ty(cx, ast::TyU8), b as u64, false),
+ ast::LitChar(i) => C_integral(Type::char(cx), i as u64, false),
+ ast::LitInt(i, ast::SignedIntLit(t, _)) => {
C_integral(Type::int_from_ty(cx, t), i, true)
}
- hir::LitInt(u, hir::UnsignedIntLit(t)) => {
+ ast::LitInt(u, ast::UnsignedIntLit(t)) => {
C_integral(Type::uint_from_ty(cx, t), u, false)
}
- hir::LitInt(i, hir::UnsuffixedIntLit(_)) => {
+ ast::LitInt(i, ast::UnsuffixedIntLit(_)) => {
let lit_int_ty = cx.tcx().node_id_to_type(e.id);
match lit_int_ty.sty {
ty::TyInt(t) => {
lit_int_ty))
}
}
- hir::LitFloat(ref fs, t) => {
+ ast::LitFloat(ref fs, t) => {
C_floating(&fs, Type::float_from_ty(cx, t))
}
- hir::LitFloatUnsuffixed(ref fs) => {
+ ast::LitFloatUnsuffixed(ref fs) => {
let lit_float_ty = cx.tcx().node_id_to_type(e.id);
match lit_float_ty.sty {
ty::TyFloat(t) => {
}
}
}
- hir::LitBool(b) => C_bool(cx, b),
- hir::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
- hir::LitByteStr(ref data) => {
- addr_of(cx, C_bytes(cx, &data[..]), "byte_str")
+ ast::LitBool(b) => C_bool(cx, b),
+ ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()),
+ ast::LitByteStr(ref data) => {
+ addr_of(cx, C_bytes(cx, &data[..]), 1, "byte_str")
}
}
}
fn addr_of_mut(ccx: &CrateContext,
cv: ValueRef,
+ align: machine::llalign,
kind: &str)
-> ValueRef {
unsafe {
// FIXME: this totally needs a better name generation scheme, perhaps a simple global
// counter? Also most other uses of gensym in trans.
let gsym = token::gensym("_");
- let name = format!("{}{}", kind, gsym.usize());
+ let name = format!("{}{}", kind, gsym.0);
let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` is already defined", name));
});
llvm::LLVMSetInitializer(gv, cv);
+ llvm::LLVMSetAlignment(gv, align);
SetLinkage(gv, InternalLinkage);
SetUnnamedAddr(gv, true);
gv
pub fn addr_of(ccx: &CrateContext,
cv: ValueRef,
+ align: machine::llalign,
kind: &str)
-> ValueRef {
match ccx.const_globals().borrow().get(&cv) {
- Some(&gv) => return gv,
+ Some(&gv) => {
+ unsafe {
+ // Upgrade the alignment in cases where the same constant is used with different
+ // alignment requirements
+ if align > llvm::LLVMGetAlignment(gv) {
+ llvm::LLVMSetAlignment(gv, align);
+ }
+ }
+ return gv;
+ }
None => {}
}
- let gv = addr_of_mut(ccx, cv, kind);
+ let gv = addr_of_mut(ccx, cv, align, kind);
unsafe {
llvm::LLVMSetGlobalConstant(gv, True);
}
node: ExprOrMethodCall,
def_id: DefId,
arg_vals: &[ValueRef],
- param_substs: &'tcx Substs<'tcx>) -> ValueRef {
+ param_substs: &'tcx Substs<'tcx>,
+ trueconst: TrueConst) -> Result<ValueRef, ConstEvalFailure> {
let fn_like = const_eval::lookup_const_fn_by_id(ccx.tcx(), def_id);
let fn_like = fn_like.expect("lookup_const_fn_by_id failed in const_fn_call");
let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs));
match fn_like.body().expr {
Some(ref expr) => {
- const_expr(ccx, &**expr, substs, Some(&fn_args)).0
- }
- None => C_nil(ccx)
+ const_expr(ccx, &**expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res)
+ },
+ None => Ok(C_nil(ccx)),
}
}
}
}
+pub enum ConstEvalFailure {
+ /// in case the const evaluator failed on something that panic at runtime
+ /// as defined in RFC 1229
+ Runtime(ConstEvalErr),
+ // in case we found a true constant
+ Compiletime(ConstEvalErr),
+}
+
+impl ConstEvalFailure {
+ fn into_inner(self) -> ConstEvalErr {
+ match self {
+ Runtime(e) => e,
+ Compiletime(e) => e,
+ }
+ }
+ pub fn description(&self) -> Cow<str> {
+ match self {
+ &Runtime(ref e) => e.description(),
+ &Compiletime(ref e) => e.description(),
+ }
+ }
+}
+
+#[derive(Copy, Clone)]
+pub enum TrueConst {
+ Yes, No
+}
+
+use self::ConstEvalFailure::*;
+
fn get_const_val(ccx: &CrateContext,
def_id: DefId,
- ref_expr: &hir::Expr) -> ValueRef {
+ ref_expr: &hir::Expr) -> Result<ValueRef, ConstEvalFailure> {
let expr = get_const_expr(ccx, def_id, ref_expr);
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
- get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(), empty_substs)
+ match get_const_expr_as_global(ccx, expr, check_const::ConstQualif::empty(),
+ empty_substs, TrueConst::Yes) {
+ Err(Runtime(err)) => {
+ ccx.tcx().sess.span_err(expr.span, &err.description());
+ Err(Compiletime(err))
+ },
+ other => other,
+ }
}
pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
expr: &hir::Expr,
qualif: check_const::ConstQualif,
- param_substs: &'tcx Substs<'tcx>)
- -> ValueRef {
+ param_substs: &'tcx Substs<'tcx>,
+ trueconst: TrueConst)
+ -> Result<ValueRef, ConstEvalFailure> {
debug!("get_const_expr_as_global: {:?}", expr.id);
// Special-case constants to cache a common global for all uses.
match expr.node {
let key = (expr.id, param_substs);
match ccx.const_values().borrow().get(&key) {
- Some(&val) => return val,
+ Some(&val) => return Ok(val),
None => {}
}
+ let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
+ &ccx.tcx().expr_ty(expr));
let val = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
// Avoid autorefs as they would create global instead of stack
// references, even when only the latter are correct.
- let ty = monomorphize::apply_param_substs(ccx.tcx(), param_substs,
- &ccx.tcx().expr_ty(expr));
- const_expr_unadjusted(ccx, expr, ty, param_substs, None)
+ try!(const_expr_unadjusted(ccx, expr, ty, param_substs, None, trueconst))
} else {
- const_expr(ccx, expr, param_substs, None).0
+ match const_expr(ccx, expr, param_substs, None, trueconst) {
+ Err(err) => return Err(err),
+ Ok((ok, _)) => ok,
+ }
};
// boolean SSA values are i1, but they have to be stored in i8 slots,
}
};
- let lvalue = addr_of(ccx, val, "const");
+ let lvalue = addr_of(ccx, val, type_of::align_of(ccx, ty), "const");
ccx.const_values().borrow_mut().insert(key, lvalue);
- lvalue
+ Ok(lvalue)
}
pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e: &hir::Expr,
param_substs: &'tcx Substs<'tcx>,
- fn_args: FnArgMap)
- -> (ValueRef, Ty<'tcx>) {
+ fn_args: FnArgMap,
+ trueconst: TrueConst)
+ -> Result<(ValueRef, Ty<'tcx>), ConstEvalFailure> {
let ety = monomorphize::apply_param_substs(cx.tcx(), param_substs,
&cx.tcx().expr_ty(e));
- let llconst = const_expr_unadjusted(cx, e, ety, param_substs, fn_args);
+ let llconst = try!(const_expr_unadjusted(cx, e, ety, param_substs, fn_args, trueconst));
let mut llconst = llconst;
let mut ety_adjusted = monomorphize::apply_param_substs(cx.tcx(), param_substs,
&cx.tcx().expr_ty_adjusted(e));
if adj.autoderefs == 0 {
// Don't copy data to do a deref+ref
// (i.e., skip the last auto-deref).
- llconst = addr_of(cx, llconst, "autoref");
+ llconst = addr_of(cx, llconst, type_of::align_of(cx, ty), "autoref");
ty = cx.tcx().mk_imm_ref(cx.tcx().mk_region(ty::ReStatic), ty);
}
} else {
e, ety_adjusted,
csize, tsize));
}
- (llconst, ety_adjusted)
+ Ok((llconst, ety_adjusted))
}
fn check_unary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
- te: ValueRef) {
+ te: ValueRef, trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
// The only kind of unary expression that we check for validity
// here is `-expr`, to check if it "overflows" (e.g. `-i32::MIN`).
if let hir::ExprUnary(hir::UnNeg, ref inner_e) = e.node {
//
// Catch this up front by looking for ExprLit directly,
// and just accepting it.
- if let hir::ExprLit(_) = inner_e.node { return; }
+ if let hir::ExprLit(_) = inner_e.node { return Ok(()); }
let result = match t.sty {
ty::TyInt(int_type) => {
let input = match const_to_opt_int(te) {
Some(v) => v,
- None => return,
+ None => return Ok(()),
};
const_int_checked_neg(
input, e, Some(const_eval::IntTy::from(cx.tcx(), int_type)))
ty::TyUint(uint_type) => {
let input = match const_to_opt_uint(te) {
Some(v) => v,
- None => return,
+ None => return Ok(()),
};
const_uint_checked_neg(
input, e, Some(const_eval::UintTy::from(cx.tcx(), uint_type)))
}
- _ => return,
+ _ => return Ok(()),
};
+ const_err(cx, e, result, trueconst)
+ } else {
+ Ok(())
+ }
+}
- // We do not actually care about a successful result.
- if let Err(err) = result {
+fn const_err(cx: &CrateContext,
+ e: &hir::Expr,
+ result: Result<ConstVal, ConstEvalErr>,
+ trueconst: TrueConst)
+ -> Result<(), ConstEvalFailure> {
+ match (result, trueconst) {
+ (Ok(_), _) => {
+ // We do not actually care about a successful result.
+ Ok(())
+ },
+ (Err(err), TrueConst::Yes) => {
cx.tcx().sess.span_err(e.span, &err.description());
- }
+ Err(Compiletime(err))
+ },
+ (Err(err), TrueConst::No) => {
+ cx.tcx().sess.span_warn(e.span, &err.description());
+ Err(Runtime(err))
+ },
}
}
fn check_binary_expr_validity(cx: &CrateContext, e: &hir::Expr, t: Ty,
- te1: ValueRef, te2: ValueRef) {
- let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { return };
+ te1: ValueRef, te2: ValueRef,
+ trueconst: TrueConst) -> Result<(), ConstEvalFailure> {
+ let b = if let hir::ExprBinary(b, _, _) = e.node { b } else { unreachable!() };
let result = match t.sty {
ty::TyInt(int_type) => {
let (lhs, rhs) = match (const_to_opt_int(te1),
const_to_opt_int(te2)) {
(Some(v1), Some(v2)) => (v1, v2),
- _ => return,
+ _ => return Ok(()),
};
let opt_ety = Some(const_eval::IntTy::from(cx.tcx(), int_type));
hir::BiRem => const_int_checked_rem(lhs, rhs, e, opt_ety),
hir::BiShl => const_int_checked_shl(lhs, rhs, e, opt_ety),
hir::BiShr => const_int_checked_shr(lhs, rhs, e, opt_ety),
- _ => return,
+ _ => return Ok(()),
}
}
ty::TyUint(uint_type) => {
let (lhs, rhs) = match (const_to_opt_uint(te1),
const_to_opt_uint(te2)) {
(Some(v1), Some(v2)) => (v1, v2),
- _ => return,
+ _ => return Ok(()),
};
let opt_ety = Some(const_eval::UintTy::from(cx.tcx(), uint_type));
hir::BiRem => const_uint_checked_rem(lhs, rhs, e, opt_ety),
hir::BiShl => const_uint_checked_shl(lhs, rhs, e, opt_ety),
hir::BiShr => const_uint_checked_shr(lhs, rhs, e, opt_ety),
- _ => return,
+ _ => return Ok(()),
}
}
- _ => return,
+ _ => return Ok(()),
};
- // We do not actually care about a successful result.
- if let Err(err) = result {
- cx.tcx().sess.span_err(e.span, &err.description());
- }
+ const_err(cx, e, result, trueconst)
}
fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e: &hir::Expr,
ety: Ty<'tcx>,
param_substs: &'tcx Substs<'tcx>,
- fn_args: FnArgMap)
- -> ValueRef
+ fn_args: FnArgMap,
+ trueconst: TrueConst)
+ -> Result<ValueRef, ConstEvalFailure>
{
debug!("const_expr_unadjusted(e={:?}, ety={:?}, param_substs={:?})",
e,
ety,
param_substs);
- let map_list = |exprs: &[P<hir::Expr>]| -> Vec<ValueRef> {
+ let map_list = |exprs: &[P<hir::Expr>]| -> Result<Vec<ValueRef>, ConstEvalFailure> {
exprs.iter()
- .map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
+ .map(|e| const_expr(cx, &**e, param_substs, fn_args, trueconst).map(|(l, _)| l))
+ .collect::<Vec<Result<ValueRef, ConstEvalFailure>>>()
+ .into_iter()
.collect()
+ // this dance is necessary to eagerly run const_expr so all errors are reported
};
let _icx = push_ctxt("const_expr");
- match e.node {
+ Ok(match e.node {
hir::ExprLit(ref lit) => {
const_lit(cx, e, &**lit)
},
hir::ExprBinary(b, ref e1, ref e2) => {
/* Neither type is bottom, and we expect them to be unified
* already, so the following is safe. */
- let (te1, ty) = const_expr(cx, &**e1, param_substs, fn_args);
+ let (te1, ty) = try!(const_expr(cx, &**e1, param_substs, fn_args, trueconst));
debug!("const_expr_unadjusted: te1={}, ty={:?}",
cx.tn().val_to_string(te1),
ty);
let is_float = ty.is_fp();
let signed = ty.is_signed();
- let (te2, _) = const_expr(cx, &**e2, param_substs, fn_args);
+ let (te2, _) = try!(const_expr(cx, &**e2, param_substs, fn_args, trueconst));
- check_binary_expr_validity(cx, e, ty, te1, te2);
+ try!(check_binary_expr_validity(cx, e, ty, te1, te2, trueconst));
unsafe { match b.node {
hir::BiAdd if is_float => llvm::LLVMConstFAdd(te1, te2),
} } // unsafe { match b.node {
},
hir::ExprUnary(u, ref inner_e) => {
- let (te, ty) = const_expr(cx, &**inner_e, param_substs, fn_args);
+ let (te, ty) = try!(const_expr(cx, &**inner_e, param_substs, fn_args, trueconst));
- check_unary_expr_validity(cx, e, ty, te);
+ try!(check_unary_expr_validity(cx, e, ty, te, trueconst));
let is_float = ty.is_fp();
unsafe { match u {
- hir::UnUniq | hir::UnDeref => const_deref(cx, te, ty).0,
- hir::UnNot => llvm::LLVMConstNot(te),
- hir::UnNeg if is_float => llvm::LLVMConstFNeg(te),
- hir::UnNeg => llvm::LLVMConstNeg(te),
+ hir::UnDeref => const_deref(cx, te, ty).0,
+ hir::UnNot => llvm::LLVMConstNot(te),
+ hir::UnNeg if is_float => llvm::LLVMConstFNeg(te),
+ hir::UnNeg => llvm::LLVMConstNeg(te),
} }
},
hir::ExprField(ref base, field) => {
- let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
+ let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
let brepr = adt::represent_type(cx, bt);
let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
- let ix = vinfo.field_index(field.node.name);
+ let ix = vinfo.field_index(field.node);
adt::const_get_field(cx, &*brepr, bv, vinfo.discr, ix)
},
hir::ExprTupField(ref base, idx) => {
- let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
+ let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
let brepr = adt::represent_type(cx, bt);
let vinfo = VariantInfo::from_ty(cx.tcx(), bt, None);
adt::const_get_field(cx, &*brepr, bv, vinfo.discr, idx.node)
},
-
hir::ExprIndex(ref base, ref index) => {
- let (bv, bt) = const_expr(cx, &**base, param_substs, fn_args);
- let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked) {
+ let (bv, bt) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
+ let iv = match eval_const_expr_partial(cx.tcx(), &index, ExprTypeChecked, None) {
Ok(ConstVal::Int(i)) => i as u64,
Ok(ConstVal::Uint(u)) => u,
_ => cx.sess().span_bug(index.span,
if iv >= len {
// FIXME #3170: report this earlier on in the const-eval
// pass. Reporting here is a bit late.
- cx.sess().span_err(e.span,
- "const index-expr is out of bounds");
- C_undef(type_of::type_of(cx, bt).element_type())
+ span_err!(cx.sess(), e.span, E0515,
+ "const index-expr is out of bounds");
+ C_undef(val_ty(arr).element_type())
} else {
const_get_elt(cx, arr, &[iv as c_uint])
}
hir::ExprCast(ref base, _) => {
let t_cast = ety;
let llty = type_of::type_of(cx, t_cast);
- let (v, t_expr) = const_expr(cx, &**base, param_substs, fn_args);
+ let (v, t_expr) = try!(const_expr(cx, &**base, param_substs, fn_args, trueconst));
debug!("trans_const_cast({:?} as {:?})", t_expr, t_cast);
if expr::cast_is_noop(cx.tcx(), base, t_expr, t_cast) {
- return v;
+ return Ok(v);
}
if type_is_fat_ptr(cx.tcx(), t_expr) {
// Fat pointer casts.
ptr_ty);
if type_is_fat_ptr(cx.tcx(), t_cast) {
let info = const_get_elt(cx, v, &[abi::FAT_PTR_EXTRA as u32]);
- return C_struct(cx, &[addr, info], false)
+ return Ok(C_struct(cx, &[addr, info], false))
} else {
- return addr;
+ return Ok(addr);
}
}
unsafe { match (
let mut cur = sub;
loop {
match cur.node {
- hir::ExprParen(ref sub) => cur = sub,
hir::ExprBlock(ref blk) => {
if let Some(ref sub) = blk.expr {
cur = sub;
} else {
// If this isn't the address of a static, then keep going through
// normal constant evaluation.
- let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
- addr_of(cx, v, "ref")
+ let (v, ty) = try!(const_expr(cx, &**sub, param_substs, fn_args, trueconst));
+ addr_of(cx, v, type_of::align_of(cx, ty), "ref")
}
},
hir::ExprAddrOf(hir::MutMutable, ref sub) => {
- let (v, _) = const_expr(cx, &**sub, param_substs, fn_args);
- addr_of_mut(cx, v, "ref_mut_slice")
+ let (v, ty) = try!(const_expr(cx, &**sub, param_substs, fn_args, trueconst));
+ addr_of_mut(cx, v, type_of::align_of(cx, ty), "ref_mut_slice")
},
hir::ExprTup(ref es) => {
let repr = adt::represent_type(cx, ety);
- let vals = map_list(&es[..]);
+ let vals = try!(map_list(&es[..]));
adt::trans_const(cx, &*repr, 0, &vals[..])
},
hir::ExprStruct(_, ref fs, ref base_opt) => {
let repr = adt::represent_type(cx, ety);
let base_val = match *base_opt {
- Some(ref base) => Some(const_expr(cx, &**base, param_substs, fn_args)),
+ Some(ref base) => Some(try!(const_expr(
+ cx,
+ &**base,
+ param_substs,
+ fn_args,
+ trueconst,
+ ))),
None => None
};
let VariantInfo { discr, fields } = VariantInfo::of_node(cx.tcx(), ety, e.id);
let cs = fields.iter().enumerate().map(|(ix, &Field(f_name, _))| {
- match (fs.iter().find(|f| f_name == f.ident.node.name), base_val) {
- (Some(ref f), _) => const_expr(cx, &*f.expr, param_substs, fn_args).0,
- (_, Some((bv, _))) => adt::const_get_field(cx, &*repr, bv, discr, ix),
+ match (fs.iter().find(|f| f_name == f.name.node), base_val) {
+ (Some(ref f), _) => {
+ const_expr(cx, &*f.expr, param_substs, fn_args, trueconst).map(|(l, _)| l)
+ },
+ (_, Some((bv, _))) => Ok(adt::const_get_field(cx, &*repr, bv, discr, ix)),
(_, None) => cx.sess().span_bug(e.span, "missing struct field"),
}
- }).collect::<Vec<_>>();
+ })
+ .collect::<Vec<Result<_, ConstEvalFailure>>>()
+ .into_iter()
+ .collect::<Result<Vec<_>,ConstEvalFailure>>();
+ let cs = try!(cs);
if ety.is_simd() {
C_vector(&cs[..])
} else {
let unit_ty = ety.sequence_element_type(cx.tcx());
let llunitty = type_of::type_of(cx, unit_ty);
let vs = es.iter()
- .map(|e| const_expr(cx, &**e, param_substs, fn_args).0)
- .collect::<Vec<_>>();
+ .map(|e| const_expr(
+ cx,
+ &**e,
+ param_substs,
+ fn_args,
+ trueconst,
+ ).map(|(l, _)| l))
+ .collect::<Vec<Result<_, ConstEvalFailure>>>()
+ .into_iter()
+ .collect::<Result<Vec<_>, ConstEvalFailure>>();
+ let vs = try!(vs);
// If the vector contains enums, an LLVM array won't work.
if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
C_struct(cx, &vs[..], false)
let unit_ty = ety.sequence_element_type(cx.tcx());
let llunitty = type_of::type_of(cx, unit_ty);
let n = cx.tcx().eval_repeat_count(count);
- let unit_val = const_expr(cx, &**elem, param_substs, fn_args).0;
+ let unit_val = try!(const_expr(cx, &**elem, param_substs, fn_args, trueconst)).0;
let vs = vec![unit_val; n];
if val_ty(unit_val) != llunitty {
C_struct(cx, &vs[..], false)
hir::ExprPath(..) => {
let def = cx.tcx().def_map.borrow().get(&e.id).unwrap().full_def();
match def {
- def::DefLocal(id) => {
+ def::DefLocal(_, id) => {
if let Some(val) = fn_args.and_then(|args| args.get(&id).cloned()) {
val
} else {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
def::DefConst(def_id) | def::DefAssociatedConst(def_id) => {
- const_deref_ptr(cx, get_const_val(cx, def_id, e))
+ const_deref_ptr(cx, try!(get_const_val(cx, def_id, e)))
}
def::DefVariant(enum_did, variant_did, _) => {
let vinfo = cx.tcx().lookup_adt_def(enum_did).variant_with_id(variant_did);
ty::VariantKind::Tuple => {
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
}
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
cx.sess().span_bug(e.span, "path-expr refers to a dict variant!")
}
}
let mut callee = &**callee;
loop {
callee = match callee.node {
- hir::ExprParen(ref inner) => &**inner,
hir::ExprBlock(ref block) => match block.expr {
Some(ref tail) => &**tail,
None => break,
};
}
let def = cx.tcx().def_map.borrow()[&callee.id].full_def();
- let arg_vals = map_list(args);
+ let arg_vals = try!(map_list(args));
match def {
def::DefFn(did, _) | def::DefMethod(did) => {
- const_fn_call(cx, ExprId(callee.id), did, &arg_vals, param_substs)
+ try!(const_fn_call(
+ cx,
+ ExprId(callee.id),
+ did,
+ &arg_vals,
+ param_substs,
+ trueconst,
+ ))
}
def::DefStruct(_) => {
if ety.is_simd() {
}
},
hir::ExprMethodCall(_, _, ref args) => {
- let arg_vals = map_list(args);
+ let arg_vals = try!(map_list(args));
let method_call = ty::MethodCall::expr(e.id);
let method_did = cx.tcx().tables.borrow().method_map[&method_call].def_id;
- const_fn_call(cx, MethodCallKey(method_call),
- method_did, &arg_vals, param_substs)
+ try!(const_fn_call(cx, MethodCallKey(method_call),
+ method_did, &arg_vals, param_substs, trueconst))
},
- hir::ExprParen(ref e) => const_expr(cx, &**e, param_substs, fn_args).0,
hir::ExprBlock(ref block) => {
match block.expr {
- Some(ref expr) => const_expr(cx, &**expr, param_substs, fn_args).0,
+ Some(ref expr) => try!(const_expr(
+ cx,
+ &**expr,
+ param_substs,
+ fn_args,
+ trueconst,
+ )).0,
None => C_nil(cx),
}
},
hir::ExprClosure(_, ref decl, ref body) => {
match ety.sty {
- ty::TyClosure(_, ref substs) => {
+ ty::TyClosure(def_id, ref substs) => {
closure::trans_closure_expr(closure::Dest::Ignore(cx), decl,
- body, e.id, substs);
+ body, e.id, def_id, substs);
}
_ =>
cx.sess().span_bug(
},
_ => cx.sess().span_bug(e.span,
"bad constant expression type in consts::const_expr"),
- }
+ })
}
+
pub fn trans_static(ccx: &CrateContext,
m: hir::Mutability,
expr: &hir::Expr,
id: ast::NodeId,
- attrs: &Vec<hir::Attribute>)
- -> ValueRef {
+ attrs: &Vec<ast::Attribute>)
+ -> Result<ValueRef, ConstEvalErr> {
unsafe {
let _icx = push_ctxt("trans_static");
let g = base::get_item_val(ccx, id);
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
- let (v, _) = const_expr(ccx, expr, empty_substs, None);
+ let (v, _) = try!(const_expr(
+ ccx,
+ expr,
+ empty_substs,
+ None,
+ TrueConst::Yes,
+ ).map_err(|e| e.into_inner()));
// boolean SSA values are i1, but they have to be stored in i8 slots,
// otherwise some LLVM optimization passes don't work as expected
ccx.statics_to_rauw().borrow_mut().push((g, new_g));
new_g
};
+ llvm::LLVMSetAlignment(g, type_of::align_of(ccx, ty));
llvm::LLVMSetInitializer(g, v);
// As an optimization, all shared statics which do not have interior
"thread_local") {
llvm::set_thread_local(g, true);
}
- g
+ Ok(g)
}
}
did: DefId,
ty: Ty<'tcx>)
-> ValueRef {
- if did.is_local() { return base::get_item_val(ccx, did.node) }
- base::trans_external_path(ccx, did, ty)
+ if let Some(node_id) = ccx.tcx().map.as_local_node_id(did) {
+ base::get_item_val(ccx, node_id)
+ } else {
+ base::trans_external_path(ccx, did, ty)
+ }
}
ifn!("llvm.trap", fn() -> void);
ifn!("llvm.debugtrap", fn() -> void);
- ifn!("llvm.frameaddress", fn(t_i32) -> i8p);
ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
use trans::debuginfo;
use trans::debuginfo::{DebugLoc, ToDebugLoc};
use trans::expr;
+use trans::machine;
use trans;
use middle::ty;
pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &hir::Expr,
- opt_label: Option<ast::Ident>,
+ opt_label: Option<ast::Name>,
exit: usize)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_break_cont");
pub fn trans_break<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &hir::Expr,
- label_opt: Option<ast::Ident>)
+ label_opt: Option<ast::Name>)
-> Block<'blk, 'tcx> {
return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_BREAK);
}
pub fn trans_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &hir::Expr,
- label_opt: Option<ast::Ident>)
+ label_opt: Option<ast::Name>)
-> Block<'blk, 'tcx> {
return trans_break_cont(bcx, expr, label_opt, cleanup::EXIT_LOOP);
}
let filename = C_str_slice(ccx, filename);
let line = C_u32(ccx, loc.line as u32);
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
- let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc");
+ let align = machine::llalign_of_min(ccx, val_ty(expr_file_line_const));
+ let expr_file_line = consts::addr_of(ccx, expr_file_line_const, align, "panic_loc");
let args = vec!(expr_file_line);
let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem);
let bcx = callee::trans_lang_call(bcx,
let filename = C_str_slice(ccx, filename);
let line = C_u32(ccx, loc.line as u32);
let file_line_const = C_struct(ccx, &[filename, line], false);
- let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc");
+ let align = machine::llalign_of_min(ccx, val_ty(file_line_const));
+ let file_line = consts::addr_of(ccx, file_line_const, align, "panic_bounds_check_loc");
let args = vec!(file_line, index, len);
let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem);
let bcx = callee::trans_lang_call(bcx,
for arg in args {
pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, _, path1| {
scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
- name: Some(path1.node.name) });
+ name: Some(path1.node) });
scope_map.insert(node_id, fn_metadata);
})
}
hir::ExprCast(ref sub_exp, _) |
hir::ExprAddrOf(_, ref sub_exp) |
hir::ExprField(ref sub_exp, _) |
- hir::ExprTupField(ref sub_exp, _) |
- hir::ExprParen(ref sub_exp) =>
+ hir::ExprTupField(ref sub_exp, _) =>
walk_expr(cx, &**sub_exp, scope_stack, scope_map),
- hir::ExprBox(ref place, ref sub_expr) => {
- place.as_ref().map(
- |e| walk_expr(cx, &**e, scope_stack, scope_map));
+ hir::ExprBox(ref sub_expr) => {
walk_expr(cx, &**sub_expr, scope_stack, scope_map);
}
use llvm;
use llvm::ValueRef;
-use trans::common::{C_bytes, CrateContext};
+use trans::common::{C_bytes, CrateContext, C_i32};
use trans::declare;
use trans::type_::Type;
use session::config::NoDebugInfo;
use std::ffi::CString;
use std::ptr;
-use rustc_front::attr;
+use syntax::attr;
/// Inserts a side-effect free instruction sequence that makes sure that the
let gdb_debug_scripts_section_global =
get_or_insert_gdb_debug_scripts_section_global(ccx);
unsafe {
+ // Load just the first byte as that's all that's necessary to force
+ // LLVM to keep around the reference to the global.
+ let indices = [C_i32(ccx, 0), C_i32(ccx, 0)];
+ let element =
+ llvm::LLVMBuildInBoundsGEP(ccx.raw_builder(),
+ gdb_debug_scripts_section_global,
+ indices.as_ptr(),
+ indices.len() as ::libc::c_uint,
+ empty.as_ptr());
let volative_load_instruction =
llvm::LLVMBuildLoad(ccx.raw_builder(),
- gdb_debug_scripts_section_global,
+ element,
empty.as_ptr());
llvm::LLVMSetVolatile(volative_load_instruction, llvm::True);
+ llvm::LLVMSetAlignment(volative_load_instruction, 1);
}
}
}
/// section.
pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
-> llvm::ValueRef {
- let section_var_name = "__rustc_debug_gdb_scripts_section__";
+ let c_section_var_name = "__rustc_debug_gdb_scripts_section__\0";
+ let section_var_name = &c_section_var_name[..c_section_var_name.len()-1];
let section_var = unsafe {
llvm::LLVMGetNamedGlobal(ccx.llmod(),
- section_var_name.as_ptr() as *const _)
+ c_section_var_name.as_ptr() as *const _)
};
if section_var == ptr::null_mut() {
use middle::pat_util;
use middle::subst::{self, Substs};
use rustc::front::map as hir_map;
-use rustc_front;
use rustc_front::hir;
use trans::{type_of, adt, machine, monomorphize};
use trans::common::{self, CrateContext, FunctionContext, Block};
use std::path::Path;
use std::ptr;
use std::rc::Rc;
+use syntax;
use syntax::util::interner::Interner;
use syntax::codemap::Span;
use syntax::{ast, codemap};
output: &mut String) {
// First, find out the 'real' def_id of the type. Items inlined from
// other crates have to be mapped back to their source.
- let source_def_id = if def_id.is_local() {
- match cx.external_srcs().borrow().get(&def_id.node).cloned() {
+ let source_def_id = if let Some(node_id) = cx.tcx().map.as_local_node_id(def_id) {
+ match cx.external_srcs().borrow().get(&node_id).cloned() {
Some(source_def_id) => {
// The given def_id identifies the inlined copy of a
// type definition, let's take the source of the copy.
output.push_str(crate_hash.as_str());
output.push_str("/");
- output.push_str(&format!("{:x}", def_id.node));
+ output.push_str(&format!("{:x}", def_id.index.as_usize()));
// Maybe check that there is no self type here.
.find_metadata_for_unique_id($unique_type_id) {
Some(metadata) => return MetadataCreationResult::new(metadata, true),
None => { /* proceed normally */ }
- };
+ }
)
}
let mut type_map = debug_context(cx).type_map.borrow_mut();
if already_stored_in_typemap {
- // Also make sure that we already have a TypeMap entry entry for the unique type id.
+ // Also make sure that we already have a TypeMap entry for the unique type id.
let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) {
Some(metadata) => metadata,
None => {
ty::TyBool => ("bool".to_string(), DW_ATE_boolean),
ty::TyChar => ("char".to_string(), DW_ATE_unsigned_char),
ty::TyInt(int_ty) => match int_ty {
- hir::TyIs => ("isize".to_string(), DW_ATE_signed),
- hir::TyI8 => ("i8".to_string(), DW_ATE_signed),
- hir::TyI16 => ("i16".to_string(), DW_ATE_signed),
- hir::TyI32 => ("i32".to_string(), DW_ATE_signed),
- hir::TyI64 => ("i64".to_string(), DW_ATE_signed)
+ ast::TyIs => ("isize".to_string(), DW_ATE_signed),
+ ast::TyI8 => ("i8".to_string(), DW_ATE_signed),
+ ast::TyI16 => ("i16".to_string(), DW_ATE_signed),
+ ast::TyI32 => ("i32".to_string(), DW_ATE_signed),
+ ast::TyI64 => ("i64".to_string(), DW_ATE_signed)
},
ty::TyUint(uint_ty) => match uint_ty {
- hir::TyUs => ("usize".to_string(), DW_ATE_unsigned),
- hir::TyU8 => ("u8".to_string(), DW_ATE_unsigned),
- hir::TyU16 => ("u16".to_string(), DW_ATE_unsigned),
- hir::TyU32 => ("u32".to_string(), DW_ATE_unsigned),
- hir::TyU64 => ("u64".to_string(), DW_ATE_unsigned)
+ ast::TyUs => ("usize".to_string(), DW_ATE_unsigned),
+ ast::TyU8 => ("u8".to_string(), DW_ATE_unsigned),
+ ast::TyU16 => ("u16".to_string(), DW_ATE_unsigned),
+ ast::TyU32 => ("u32".to_string(), DW_ATE_unsigned),
+ ast::TyU64 => ("u64".to_string(), DW_ATE_unsigned)
},
ty::TyFloat(float_ty) => match float_ty {
- hir::TyF32 => ("f32".to_string(), DW_ATE_float),
- hir::TyF64 => ("f64".to_string(), DW_ATE_float),
+ ast::TyF32 => ("f32".to_string(), DW_ATE_float),
+ ast::TyF64 => ("f64".to_string(), DW_ATE_float),
},
_ => cx.sess().bug("debuginfo::basic_type_metadata - t is invalid type")
};
let sole_struct_member_description = MemberDescription {
name: match non_null_variant.kind() {
ty::VariantKind::Tuple => "__0".to_string(),
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
non_null_variant.fields[0].name.to_string()
}
ty::VariantKind::Unit => unreachable!()
.map(|(i, _)| format!("__{}", i))
.collect()
}
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
variant.fields
.iter()
.map(|f| f.name.to_string())
})
.collect();
- let discriminant_type_metadata = |inttype: rustc_front::attr::IntType| {
+ let discriminant_type_metadata = |inttype: syntax::attr::IntType| {
let disr_type_key = (enum_def_id, inttype);
let cached_discriminant_type_metadata = debug_context(cx).created_enum_disr_types
.borrow()
let (name, span) = match var_item {
hir_map::NodeItem(item) => {
match item.node {
- hir::ItemStatic(..) => (item.ident.name, item.span),
- hir::ItemConst(..) => (item.ident.name, item.span),
+ hir::ItemStatic(..) => (item.name, item.span),
+ hir::ItemConst(..) => (item.name, item.span),
_ => {
cx.sess()
.span_bug(item.span,
let is_local_to_unit = is_node_local_to_unit(cx, node_id);
let variable_type = cx.tcx().node_id_to_type(node_id);
let type_metadata = type_metadata(cx, variable_type, span);
- let namespace_node = namespace_for_item(cx, DefId::local(node_id));
+ let node_def_id = cx.tcx().map.local_def_id(node_id);
+ let namespace_node = namespace_for_item(cx, node_def_id);
let var_name = name.to_string();
let linkage_name =
namespace_node.mangled_name_of_contained_item(&var_name[..]);
let def_map = &cx.tcx().def_map;
let locals = bcx.fcx.lllocals.borrow();
- pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, var_ident| {
+ pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, var_name| {
let datum = match locals.get(&node_id) {
Some(datum) => datum,
None => {
let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
declare_local(bcx,
- var_ident.node.name,
+ var_name.node,
datum.ty,
scope_metadata,
VariableAccess::DirectVariable { alloca: datum.val },
None => {
cx.sess().span_bug(span, "debuginfo::create_captured_var_metadata: node not found");
}
- Some(hir_map::NodeLocal(pat)) | Some(hir_map::NodeArg(pat)) => {
+ Some(hir_map::NodeLocal(pat)) => {
match pat.node {
hir::PatIdent(_, ref path1, _) => {
path1.node.name
.fn_metadata;
let locals = bcx.fcx.lllocals.borrow();
- pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, var_ident| {
+ pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, var_name| {
let datum = match locals.get(&node_id) {
Some(v) => v,
None => {
};
declare_local(bcx,
- var_ident.node.name,
+ var_name.node,
datum.ty,
scope_metadata,
VariableAccess::DirectVariable { alloca: datum.val },
use middle::subst::{self, Substs};
use rustc_front;
use rustc_front::hir;
-use rustc_front::attr::IntType;
use trans::common::{NodeIdAndSpan, CrateContext, FunctionContext, Block};
use trans;
use syntax::codemap::{Span, Pos};
use syntax::{abi, ast, codemap};
+use syntax::attr::IntType;
use syntax::parse::token::{self, special_idents};
pub mod gdb;
match item.node {
hir::ItemFn(ref fn_decl, _, _, _, ref generics, ref top_level_block) => {
- (item.ident.name, fn_decl, generics, top_level_block, item.span, true)
+ (item.name, fn_decl, generics, top_level_block, item.span, true)
}
_ => {
cx.sess().span_bug(item.span,
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
- (impl_item.ident.name,
+ (impl_item.name,
&sig.decl,
&sig.generics,
body,
return FunctionDebugContext::FunctionWithoutDebugInfo;
}
- (trait_item.ident.name,
+ (trait_item.name,
&sig.decl,
&sig.generics,
body,
// somehow (storing a path in the hir_map, or construct a path using the
// enclosing function).
let (linkage_name, containing_scope) = if has_path {
- let namespace_node = namespace_for_item(cx, DefId::local(fn_ast_id));
+ let fn_ast_def_id = cx.tcx().map.local_def_id(fn_ast_id);
+ let namespace_node = namespace_for_item(cx, fn_ast_def_id);
let linkage_name = namespace_node.mangled_name_of_contained_item(
&function_name[..]);
let containing_scope = namespace_node.scope;
// Handle other generic parameters
let actual_types = param_substs.types.get_slice(subst::FnSpace);
- for (index, &hir::TyParam{ ident, .. }) in generics.ty_params.iter().enumerate() {
+ for (index, &hir::TyParam{ name, .. }) in generics.ty_params.iter().enumerate() {
let actual_type = actual_types[index];
// Add actual type name to <...> clause of function name
let actual_type_name = compute_debuginfo_type_name(cx,
// Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == FullDebugInfo {
let actual_type_metadata = type_metadata(cx, actual_type, codemap::DUMMY_SP);
- let name = CString::new(ident.name.as_str().as_bytes()).unwrap();
+ let name = CString::new(name.as_str().as_bytes()).unwrap();
let param_metadata = unsafe {
llvm::LLVMDIBuilderCreateTemplateTypeParameter(
DIB(cx),
use middle::ty::{self, Ty};
use rustc_front::hir;
-
+use syntax::ast;
// Compute the name of the type as it should be stored in debuginfo. Does not do
// any caching, i.e. calling the function twice with the same type will also do
ty::TyBool => output.push_str("bool"),
ty::TyChar => output.push_str("char"),
ty::TyStr => output.push_str("str"),
- ty::TyInt(hir::TyIs) => output.push_str("isize"),
- ty::TyInt(hir::TyI8) => output.push_str("i8"),
- ty::TyInt(hir::TyI16) => output.push_str("i16"),
- ty::TyInt(hir::TyI32) => output.push_str("i32"),
- ty::TyInt(hir::TyI64) => output.push_str("i64"),
- ty::TyUint(hir::TyUs) => output.push_str("usize"),
- ty::TyUint(hir::TyU8) => output.push_str("u8"),
- ty::TyUint(hir::TyU16) => output.push_str("u16"),
- ty::TyUint(hir::TyU32) => output.push_str("u32"),
- ty::TyUint(hir::TyU64) => output.push_str("u64"),
- ty::TyFloat(hir::TyF32) => output.push_str("f32"),
- ty::TyFloat(hir::TyF64) => output.push_str("f64"),
+ ty::TyInt(ast::TyIs) => output.push_str("isize"),
+ ty::TyInt(ast::TyI8) => output.push_str("i8"),
+ ty::TyInt(ast::TyI16) => output.push_str("i16"),
+ ty::TyInt(ast::TyI32) => output.push_str("i32"),
+ ty::TyInt(ast::TyI64) => output.push_str("i64"),
+ ty::TyUint(ast::TyUs) => output.push_str("usize"),
+ ty::TyUint(ast::TyU8) => output.push_str("u8"),
+ ty::TyUint(ast::TyU16) => output.push_str("u16"),
+ ty::TyUint(ast::TyU32) => output.push_str("u32"),
+ ty::TyUint(ast::TyU64) => output.push_str("u64"),
+ ty::TyFloat(ast::TyF32) => output.push_str("f32"),
+ ty::TyFloat(ast::TyF64) => output.push_str("f64"),
ty::TyStruct(def, substs) |
ty::TyEnum(def, substs) => {
push_item_name(cx, def.did, qualified, output);
use trans::common::{CrateContext, FunctionContext};
use trans::type_::Type;
-use rustc_front::hir;
-
use syntax::codemap::Span;
use syntax::{ast, codemap};
};
}
-pub fn contains_nodebug_attribute(attributes: &[hir::Attribute]) -> bool {
+pub fn contains_nodebug_attribute(attributes: &[ast::Attribute]) -> bool {
attributes.iter().any(|attr| {
- let meta_item: &hir::MetaItem = &*attr.node.value;
+ let meta_item: &ast::MetaItem = &*attr.node.value;
match meta_item.node {
- hir::MetaWord(ref value) => &value[..] == "no_debug",
+ ast::MetaWord(ref value) => &value[..] == "no_debug",
_ => false
}
})
pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
-> (DIScope, Span) {
let containing_scope = namespace_for_item(cx, def_id).scope;
- let definition_span = if def_id.is_local() {
- cx.tcx().map.span(def_id.node)
- } else {
- // For external items there is no span information
- codemap::DUMMY_SP
- };
+ let definition_span = cx.tcx().map.def_id_span(def_id, codemap::DUMMY_SP /* (1) */ );
+
+ // (1) For external items there is no span information
(containing_scope, definition_span)
}
use rustc_front;
use rustc_front::hir;
-use syntax::{ast, codemap};
+use syntax::{ast, ast_util, codemap};
use syntax::parse::token::InternedString;
use syntax::ptr::P;
use syntax::parse::token;
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
- if bcx.tcx().tables.borrow().adjustments.contains_key(&expr.id) {
+ if adjustment_required(bcx, expr) {
// use trans, which may be less efficient but
// which will perform the adjustments:
let datum = unpack_datum!(bcx, trans(bcx, expr));
) {
if !qualif.intersects(check_const::ConstQualif::PREFER_IN_PLACE) {
if let SaveIn(lldest) = dest {
- let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
- bcx.fcx.param_substs);
- // Cast pointer to destination, because constants
- // have different types.
- let lldest = PointerCast(bcx, lldest, val_ty(global));
- memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
- return bcx;
+ match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
+ bcx.fcx.param_substs,
+ consts::TrueConst::No) {
+ Ok(global) => {
+ // Cast pointer to destination, because constants
+ // have different types.
+ let lldest = PointerCast(bcx, lldest, val_ty(global));
+ memcpy_ty(bcx, lldest, global, expr_ty_adjusted(bcx, expr));
+ return bcx;
+ },
+ Err(consts::ConstEvalFailure::Runtime(_)) => {
+ // in case const evaluation errors, translate normally
+ // debug assertions catch the same errors
+ // see RFC 1229
+ },
+ Err(consts::ConstEvalFailure::Compiletime(_)) => {
+ return bcx;
+ },
+ }
}
// Even if we don't have a value to emit, and the expression
// doesn't have any side-effects, we still have to translate the
check_const::ConstQualif::NOT_CONST |
check_const::ConstQualif::NEEDS_DROP
) {
- let global = consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
- bcx.fcx.param_substs);
+ match consts::get_const_expr_as_global(bcx.ccx(), expr, qualif,
+ bcx.fcx.param_substs,
+ consts::TrueConst::No) {
+ Ok(global) => {
+ if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
+ // Is borrowed as 'static, must return lvalue.
+
+ // Cast pointer to global, because constants have different types.
+ let const_ty = expr_ty_adjusted(bcx, expr);
+ let llty = type_of::type_of(bcx.ccx(), const_ty);
+ let global = PointerCast(bcx, global, llty.ptr_to());
+ let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
+ return DatumBlock::new(bcx, datum.to_expr_datum());
+ }
- if qualif.intersects(check_const::ConstQualif::HAS_STATIC_BORROWS) {
- // Is borrowed as 'static, must return lvalue.
+ // Otherwise, keep around and perform adjustments, if needed.
+ let const_ty = if adjusted_global {
+ expr_ty_adjusted(bcx, expr)
+ } else {
+ expr_ty(bcx, expr)
+ };
- // Cast pointer to global, because constants have different types.
- let const_ty = expr_ty_adjusted(bcx, expr);
- let llty = type_of::type_of(bcx.ccx(), const_ty);
- let global = PointerCast(bcx, global, llty.ptr_to());
- let datum = Datum::new(global, const_ty, Lvalue::new("expr::trans"));
- return DatumBlock::new(bcx, datum.to_expr_datum());
+ // This could use a better heuristic.
+ Some(if type_is_immediate(bcx.ccx(), const_ty) {
+ // Cast pointer to global, because constants have different types.
+ let llty = type_of::type_of(bcx.ccx(), const_ty);
+ let global = PointerCast(bcx, global, llty.ptr_to());
+ // Maybe just get the value directly, instead of loading it?
+ immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
+ } else {
+ let scratch = alloc_ty(bcx, const_ty, "const");
+ call_lifetime_start(bcx, scratch);
+ let lldest = if !const_ty.is_structural() {
+ // Cast pointer to slot, because constants have different types.
+ PointerCast(bcx, scratch, val_ty(global))
+ } else {
+ // In this case, memcpy_ty calls llvm.memcpy after casting both
+ // source and destination to i8*, so we don't need any casts.
+ scratch
+ };
+ memcpy_ty(bcx, lldest, global, const_ty);
+ Datum::new(scratch, const_ty, Rvalue::new(ByRef))
+ })
+ },
+ Err(consts::ConstEvalFailure::Runtime(_)) => {
+ // in case const evaluation errors, translate normally
+ // debug assertions catch the same errors
+ // see RFC 1229
+ None
+ },
+ Err(consts::ConstEvalFailure::Compiletime(_)) => {
+ // generate a dummy llvm value
+ let const_ty = expr_ty(bcx, expr);
+ let llty = type_of::type_of(bcx.ccx(), const_ty);
+ let dummy = C_undef(llty.ptr_to());
+ Some(Datum::new(dummy, const_ty, Rvalue::new(ByRef)))
+ },
}
-
- // Otherwise, keep around and perform adjustments, if needed.
- let const_ty = if adjusted_global {
- expr_ty_adjusted(bcx, expr)
- } else {
- expr_ty(bcx, expr)
- };
-
- // This could use a better heuristic.
- Some(if type_is_immediate(bcx.ccx(), const_ty) {
- // Cast pointer to global, because constants have different types.
- let llty = type_of::type_of(bcx.ccx(), const_ty);
- let global = PointerCast(bcx, global, llty.ptr_to());
- // Maybe just get the value directly, instead of loading it?
- immediate_rvalue(load_ty(bcx, global, const_ty), const_ty)
- } else {
- let scratch = alloc_ty(bcx, const_ty, "const");
- call_lifetime_start(bcx, scratch);
- let lldest = if !const_ty.is_structural() {
- // Cast pointer to slot, because constants have different types.
- PointerCast(bcx, scratch, val_ty(global))
- } else {
- // In this case, memcpy_ty calls llvm.memcpy after casting both
- // source and destination to i8*, so we don't need any casts.
- scratch
- };
- memcpy_ty(bcx, lldest, global, const_ty);
- Datum::new(scratch, const_ty, Rvalue::new(ByRef))
- })
} else {
None
};
}
}
+fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
+ expr: &hir::Expr) -> bool {
+ let adjustment = match bcx.tcx().tables.borrow().adjustments.get(&expr.id).cloned() {
+ None => { return false; }
+ Some(adj) => adj
+ };
+
+ // Don't skip a conversion from Box<T> to &T, etc.
+ if bcx.tcx().is_overloaded_autoderef(expr.id, 0) {
+ return true;
+ }
+
+ match adjustment {
+ AdjustReifyFnPointer => {
+ // FIXME(#19925) once fn item types are
+ // zero-sized, we'll need to return true here
+ false
+ }
+ AdjustUnsafeFnPointer => {
+ // purely a type-level thing
+ false
+ }
+ AdjustDerefRef(ref adj) => {
+ // We are a bit paranoid about adjustments and thus might have a re-
+ // borrow here which merely derefs and then refs again (it might have
+ // a different region or mutability, but we don't care here).
+ !(adj.autoderefs == 1 && adj.autoref.is_some() && adj.unsize.is_none())
+ }
+ }
+}
+
/// Helper for trans that apply adjustments from `expr` to `datum`, which should be the unadjusted
/// translation of `expr`.
fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
Rvalue::new(ByRef)));
} else {
// Otherwise, simply copy the data from the source.
- assert_eq!(src_ty, target_ty);
+ assert!(src_ty.is_phantom_data() || src_ty == target_ty);
memcpy_ty(bcx, ll_target, ll_source, src_ty);
}
}
let _icx = push_ctxt("trans_datum_unadjusted");
match expr.node {
- hir::ExprParen(ref e) => {
- trans(bcx, &**e)
- }
hir::ExprPath(..) => {
trans_def(bcx, expr, bcx.def(expr.id))
}
- hir::ExprField(ref base, ident) => {
- trans_rec_field(bcx, &**base, ident.node.name)
+ hir::ExprField(ref base, name) => {
+ trans_rec_field(bcx, &**base, name.node)
}
hir::ExprTupField(ref base, idx) => {
trans_rec_tup_field(bcx, &**base, idx.node)
hir::ExprIndex(ref base, ref idx) => {
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
}
- hir::ExprBox(_, ref contents) => {
+ hir::ExprBox(ref contents) => {
// Special case for `Box<T>`
let box_ty = expr_ty(bcx, expr);
let contents_ty = expr_ty(bcx, &**contents);
let const_ty = expr_ty(bcx, ref_expr);
// For external constants, we don't inline.
- let val = if did.is_local() {
+ let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
// Case 1.
// The LLVM global has the type of its initializer,
// which may not be equal to the enum's type for
// non-C-like enums.
- let val = base::get_item_val(bcx.ccx(), did.node);
+ let val = base::get_item_val(bcx.ccx(), node_id);
let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
PointerCast(bcx, val, pty)
} else {
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
match expr.node {
- hir::ExprParen(ref e) => {
- trans_into(bcx, &**e, Ignore)
- }
hir::ExprBreak(label_opt) => {
- controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node))
+ controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node.name))
}
hir::ExprAgain(label_opt) => {
- controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node))
+ controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node.name))
}
hir::ExprRet(ref ex) => {
// Check to see if the return expression itself is reachable.
}
}
hir::ExprAssignOp(op, ref dst, ref src) => {
- trans_assign_op(bcx, expr, op, &**dst, &**src)
+ let has_method_map = bcx.tcx()
+ .tables
+ .borrow()
+ .method_map
+ .contains_key(&MethodCall::expr(expr.id));
+
+ if has_method_map {
+ let dst = unpack_datum!(bcx, trans(bcx, &**dst));
+ let src_datum = unpack_datum!(bcx, trans(bcx, &**src));
+ trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
+ Some((src_datum, src.id)), None, false).bcx
+ } else {
+ trans_assign_op(bcx, expr, op, &**dst, &**src)
+ }
}
hir::ExprInlineAsm(ref a) => {
asm::trans_inline_asm(bcx, a)
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
match expr.node {
- hir::ExprParen(ref e) => {
- trans_into(bcx, &**e, dest)
- }
hir::ExprPath(..) => {
trans_def_dps_unadjusted(bcx, expr, bcx.def(expr.id), dest)
}
// trans. Shudder.
fn make_field(field_name: &str, expr: P<hir::Expr>) -> hir::Field {
hir::Field {
- ident: codemap::dummy_spanned(token::str_to_ident(field_name)),
+ name: codemap::dummy_spanned(token::intern(field_name)),
expr: expr,
span: codemap::DUMMY_SP,
}
}
hir::ExprLit(ref lit) => {
match lit.node {
- hir::LitStr(ref s, _) => {
+ ast::LitStr(ref s, _) => {
tvec::trans_lit_str(bcx, expr, (*s).clone(), dest)
}
_ => {
SaveIn(lldest) => closure::Dest::SaveIn(bcx, lldest),
Ignore => closure::Dest::Ignore(bcx.ccx())
};
- let substs = match expr_ty(bcx, expr).sty {
- ty::TyClosure(_, ref substs) => substs,
+
+ // NB. To get the id of the closure, we don't use
+ // `local_def_id(id)`, but rather we extract the closure
+ // def-id from the expr's type. This is because this may
+ // be an inlined expression from another crate, and we
+ // want to get the ORIGINAL closure def-id, since that is
+ // the key we need to find the closure-kind and
+ // closure-type etc.
+ let (def_id, substs) = match expr_ty(bcx, expr).sty {
+ ty::TyClosure(def_id, ref substs) => (def_id, substs),
ref t =>
bcx.tcx().sess.span_bug(
expr.span,
&format!("closure expr without closure type: {:?}", t)),
};
- closure::trans_closure_expr(dest, decl, body, expr.id, substs).unwrap_or(bcx)
+
+ closure::trans_closure_expr(dest, decl, body, expr.id, def_id, substs).unwrap_or(bcx)
}
hir::ExprCall(ref f, ref args) => {
if bcx.tcx().is_method_call(expr.id) {
// Trait casts used to come this way, now they should be coercions.
bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)")
}
- hir::ExprAssignOp(op, ref dst, ref src) => {
- trans_assign_op(bcx, expr, op, &**dst, &**src)
+ hir::ExprAssignOp(op, _, _) => {
+ bcx.tcx().sess.span_bug(
+ expr.span,
+ &format!("augmented assignment `{}=` should always be a rvalue_stmt",
+ rustc_front::util::binop_to_string(op.node)))
}
_ => {
bcx.tcx().sess.span_bug(
let _icx = push_ctxt("trans_local_var");
match def {
- def::DefUpvar(nid, _, _) => {
+ def::DefUpvar(_, nid, _, _) => {
// Can't move upvars, so this is never a ZeroMemLastUse.
let local_ty = node_id_type(bcx, nid);
let lval = Lvalue::new_with_hint("expr::trans_local_var (upvar)",
}
}
}
- def::DefLocal(nid) => {
+ def::DefLocal(_, nid) => {
let datum = match bcx.fcx.lllocals.borrow().get(&nid) {
Some(&v) => v,
None => {
let mut need_base = vec![true; vinfo.fields.len()];
let numbered_fields = fields.iter().map(|field| {
- let pos = vinfo.field_index(field.ident.node.name);
+ let pos = vinfo.field_index(field.name.node);
need_base[pos] = false;
(pos, &*field.expr)
}).collect::<Vec<_>>();
fn trans_immediate_lit<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &hir::Expr,
- lit: &hir::Lit)
+ lit: &ast::Lit)
-> DatumBlock<'blk, 'tcx, Expr> {
// must not be a string constant, that is a RvalueDpsExpr
let _icx = push_ctxt("trans_immediate_lit");
};
immediate_rvalue_bcx(bcx, llneg, un_ty).to_expr_datumblock()
}
- hir::UnUniq => {
- trans_uniq_expr(bcx, expr, un_ty, sub_expr, expr_ty(bcx, sub_expr))
- }
hir::UnDeref => {
let datum = unpack_datum!(bcx, trans(bcx, sub_expr));
deref_once(bcx, expr, datum, method_call)
immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
}
-fn ref_fat_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- lval: Datum<'tcx, Lvalue>)
- -> DatumBlock<'blk, 'tcx, Expr> {
- let dest_ty = bcx.tcx().mk_imm_ref(bcx.tcx().mk_region(ty::ReStatic), lval.ty);
- let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
- memcpy_ty(bcx, scratch.val, lval.val, scratch.ty);
-
- DatumBlock::new(bcx, scratch.to_expr_datum())
-}
-
fn trans_addr_of<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
expr: &hir::Expr,
subexpr: &hir::Expr)
let _icx = push_ctxt("trans_addr_of");
let mut bcx = bcx;
let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
+ let ty = expr_ty(bcx, expr);
if !type_is_sized(bcx.tcx(), sub_datum.ty) {
- // DST lvalue, close to a fat pointer
- ref_fat_ptr(bcx, sub_datum)
+ // Always generate an lvalue datum, because this pointer doesn't own
+ // the data and cleanup is scheduled elsewhere.
+ DatumBlock::new(bcx, Datum::new(sub_datum.val, ty, LvalueExpr(sub_datum.kind)))
} else {
// Sized value, ref to a thin pointer
- let ty = expr_ty(bcx, expr);
immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
}
}
bcx.ccx().get_intrinsic(&name)
}
fn to_intrinsic_name(&self, tcx: &ty::ctxt, ty: Ty) -> &'static str {
- use rustc_front::hir::IntTy::*;
- use rustc_front::hir::UintTy::*;
+ use syntax::ast::IntTy::*;
+ use syntax::ast::UintTy::*;
use middle::ty::{TyInt, TyUint};
let new_sty = match ty.sty {
// Note that the mask's value is derived from the LHS type
// (since that is where the 32/64 distinction is relevant) but
// the mask's type must match the RHS type (since they will
- // both be fed into a and-binop)
+ // both be fed into an and-binop)
let invert_mask = shift_mask_val(bcx, lhs_llty, rhs_llty, true);
let outer_bits = And(bcx, rhs, invert_mask, binop_debug_loc);
ExprKind::RvalueDps
}
- hir::ExprLit(ref lit) if rustc_front::util::lit_is_str(&**lit) => {
+ hir::ExprLit(ref lit) if ast_util::lit_is_str(&**lit) => {
ExprKind::RvalueDps
}
hir::ExprLit(_) | // Note: LitStr is carved out above
hir::ExprUnary(..) |
- hir::ExprBox(None, _) |
+ hir::ExprBox(_) |
hir::ExprAddrOf(..) |
hir::ExprBinary(..) |
hir::ExprCast(..) => {
ExprKind::RvalueDatum
}
-
- hir::ExprBox(Some(ref place), _) => {
- // Special case `Box<T>` for now:
- let def_id = match tcx.def_map.borrow().get(&place.id) {
- Some(def) => def.def_id(),
- None => panic!("no def for place"),
- };
- if tcx.lang_items.exchange_heap() == Some(def_id) {
- ExprKind::RvalueDatum
- } else {
- ExprKind::RvalueDps
- }
- }
-
- hir::ExprParen(ref e) => expr_kind(tcx, &**e),
}
}
use trans::type_::Type;
use trans::type_of::*;
use trans::type_of;
+use middle::infer;
use middle::ty::{self, Ty};
use middle::subst::Substs;
-use rustc::front::map as hir_map;
use std::cmp;
+use std::iter::once;
use libc::c_uint;
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
use syntax::abi::{PlatformIntrinsic, RustIntrinsic, Rust, RustCall, Stdcall, Fastcall, System};
+use syntax::attr;
use syntax::codemap::Span;
use syntax::parse::token::{InternedString, special_idents};
use syntax::ast;
use rustc_front::print::pprust;
-use rustc_front::attr;
use rustc_front::hir;
///////////////////////////////////////////////////////////////////////////
pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
abi: Abi, fty: Ty<'tcx>,
name: &str,
- attrs: &[hir::Attribute])-> ValueRef {
+ attrs: &[ast::Attribute])-> ValueRef {
debug!("register_foreign_item_fn(abi={:?}, \
ty={:?}, \
name={})",
_ => ccx.sess().bug("trans_native_call called on non-function type")
};
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
+ let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
let llsig = foreign_signature(ccx, &fn_sig, &passed_arg_tys[..]);
let fn_type = cabi::compute_abi_info(ccx,
&llsig.llarg_tys,
-> ValueRef {
let _icx = push_ctxt("foreign::register_foreign_fn");
- let tys = foreign_types_for_id(ccx, node_id);
- let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let t = ccx.tcx().node_id_to_type(node_id);
let cconv = match t.sty {
ty::TyBareFn(_, ref fn_ty) => {
}
_ => panic!("expected bare fn in register_rust_fn_with_foreign_abi")
};
+ let tys = foreign_types_for_fn_ty(ccx, t);
+ let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
add_argument_attributes(&tys, llfn);
debug!("register_rust_fn_with_foreign_abi(node_id={}, llfn_ty={}, llfn={})",
pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
decl: &hir::FnDecl,
body: &hir::Block,
- attrs: &[hir::Attribute],
+ attrs: &[ast::Attribute],
llwrapfn: ValueRef,
param_substs: &'tcx Substs<'tcx>,
id: ast::NodeId,
decl: &hir::FnDecl,
body: &hir::Block,
param_substs: &'tcx Substs<'tcx>,
- attrs: &[hir::Attribute],
+ attrs: &[ast::Attribute],
id: ast::NodeId,
hash: Option<&str>)
-> ValueRef
let t = tcx.node_id_to_type(id);
let t = monomorphize::apply_param_substs(tcx, param_substs, &t);
- let ps = ccx.tcx().map.with_path(id, |path| {
- let abi = Some(hir_map::PathName(special_idents::clownshoe_abi.name));
- link::mangle(path.chain(abi), hash)
- });
+ let path =
+ tcx.map.def_path_from_id(id)
+ .into_iter()
+ .map(|e| e.data.as_interned_str())
+ .chain(once(special_idents::clownshoe_abi.name.as_str()));
+ let ps = link::mangle(path, hash);
// Compute the type that the function would have if it were just a
// normal Rust function. This will be the type of the wrappee fn.
Some(ln) => ln.clone(),
None => match weak_lang_items::link_name(&i.attrs) {
Some(name) => name,
- None => i.ident.name.as_str(),
+ None => i.name.as_str(),
}
}
}
}
}
-fn foreign_types_for_id<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- id: ast::NodeId) -> ForeignTypes<'tcx> {
- foreign_types_for_fn_ty(ccx, ccx.tcx().node_id_to_type(id))
-}
-
fn foreign_types_for_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ty: Ty<'tcx>) -> ForeignTypes<'tcx> {
let fn_sig = match ty.sty {
_ => ccx.sess().bug("foreign_types_for_fn_ty called on non-function type")
};
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
+ let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
let llsig = foreign_signature(ccx, &fn_sig, &fn_sig.inputs);
let fn_ty = cabi::compute_abi_info(ccx,
&llsig.llarg_tys,
/// Skips the dtor, if any, for ty; drops the contents directly.
/// Note that the dtor is only skipped at the most *shallow*
/// level, namely, an `impl Drop for Ty` itself. So, for example,
- /// if Ty is Newtype(S) then only the Drop impl for for Newtype
- /// itself will be skipped, while the Drop impl for S, if any,
- /// will be invoked.
+ /// if Ty is Newtype(S) then only the Drop impl for Newtype itself
+ /// will be skipped, while the Drop impl for S, if any, will be
+ /// invoked.
TyContents(Ty<'tcx>),
}
// Already inline
debug!("instantiate_inline({}): already inline as node id {}",
ccx.tcx().item_path_str(fn_id), node_id);
- return Some(DefId::local(node_id));
+ let node_def_id = ccx.tcx().map.local_def_id(node_id);
+ return Some(node_def_id);
}
Some(&None) => {
return None; // Not inlinable
let csearch_result =
csearch::maybe_get_item_ast(
ccx.tcx(), fn_id,
- Box::new(|a,b,c,d| astencode::decode_inlined_item(a, b, c, d)));
+ Box::new(astencode::decode_inlined_item));
let inline_id = match csearch_result {
csearch::FoundAst::NotFound => {
let ty_vs = &ccx.tcx().lookup_adt_def(parent_id).variants;
assert_eq!(ast_vs.len(), ty_vs.len());
for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) {
- if ty_v.did == fn_id { my_id = ast_v.node.id; }
- ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.id));
+ if ty_v.did == fn_id { my_id = ast_v.node.data.id(); }
+ ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id()));
}
}
hir::ItemStruct(ref struct_def, _) => {
- match struct_def.ctor_id {
- None => ccx.sess().bug("instantiate_inline: called on a \
- non-tuple struct"),
- Some(ctor_id) => {
- ccx.external().borrow_mut().insert(fn_id, Some(ctor_id));
- my_id = ctor_id;
- }
+ if struct_def.is_struct() {
+ ccx.sess().bug("instantiate_inline: called on a \
+ non-tuple struct")
+ } else {
+ ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id()));
+ my_id = struct_def.id();
}
}
_ => ccx.sess().bug("instantiate_inline: item has a \
// reuse that code, it needs to be able to look up the traits for
// inlined items.
let ty_trait_item = ccx.tcx().impl_or_trait_item(fn_id).clone();
+ let trait_item_def_id = ccx.tcx().map.local_def_id(trait_item.id);
ccx.tcx().impl_or_trait_items.borrow_mut()
- .insert(DefId::local(trait_item.id), ty_trait_item);
+ .insert(trait_item_def_id, ty_trait_item);
// If this is a default method, we can't look up the
// impl type. But we aren't going to translate anyways, so
}
};
- Some(DefId::local(inline_id))
+ let inline_def_id = ccx.tcx().map.local_def_id(inline_id);
+ Some(inline_def_id)
}
pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId)
-> Option<DefId> {
- if fn_id.is_local() {
+ if let Some(_) = ccx.tcx().map.as_local_node_id(fn_id) {
Some(fn_id)
} else {
instantiate_inline(ccx, fn_id)
use syntax::ptr::P;
use syntax::parse::token;
+use rustc::session::Session;
+use syntax::codemap::Span;
+
use std::cmp::Ordering;
pub fn get_simple_intrinsic(ccx: &CrateContext, item: &hir::ForeignItem) -> Option<ValueRef> {
- let name = match &*item.ident.name.as_str() {
+ let name = match &*item.name.as_str() {
"sqrtf32" => "llvm.sqrt.f32",
"sqrtf64" => "llvm.sqrt.f64",
"powif32" => "llvm.powi.f32",
Some(ccx.get_intrinsic(&name))
}
+pub fn span_transmute_size_error(a: &Session, b: Span, msg: &str) {
+ span_err!(a, b, E0512, "{}", msg);
+}
+
/// Performs late verification that intrinsics are used correctly. At present,
/// the only intrinsic that needs such verification is `transmute`.
pub fn check_intrinsics(ccx: &CrateContext) {
last_failing_id = Some(transmute_restriction.id);
if transmute_restriction.original_from != transmute_restriction.substituted_from {
- ccx.sess().span_err(
- transmute_restriction.span,
- &format!("transmute called on types with potentially different sizes: \
+ span_transmute_size_error(ccx.sess(), transmute_restriction.span,
+ &format!("transmute called with differently sized types: \
{} (could be {} bit{}) to {} (could be {} bit{})",
transmute_restriction.original_from,
from_type_size as usize,
to_type_size as usize,
if to_type_size == 1 {""} else {"s"}));
} else {
- ccx.sess().span_err(
- transmute_restriction.span,
- &format!("transmute called on types with different sizes: \
+ span_transmute_size_error(ccx.sess(), transmute_restriction.span,
+ &format!("transmute called with differently sized types: \
{} ({} bit{}) to {} ({} bit{})",
transmute_restriction.original_from,
from_type_size as usize,
_ => panic!("expected bare_fn in trans_intrinsic_call")
};
let foreign_item = tcx.map.expect_foreign_item(node);
- let name = foreign_item.ident.name.as_str();
+ let name = foreign_item.name.as_str();
// For `transmute` we can just trans the input expr directly into dest
if name == "transmute" {
(_, "return_address") => {
if !fcx.caller_expects_out_pointer {
- tcx.sess.span_err(call_info.span,
- "invalid use of `return_address` intrinsic: function \
- does not use out pointer");
+ span_err!(tcx.sess, call_info.span, E0510,
+ "invalid use of `return_address` intrinsic: function \
+ does not use out pointer");
C_null(Type::i8p(ccx))
} else {
PointerCast(bcx, llvm::get_param(fcx.llfn, 0), Type::i8p(ccx))
(_, _) => {
let intr = match Intrinsic::find(tcx, &name) {
Some(intr) => intr,
- None => ccx.sess().span_bug(foreign_item.span, "unknown intrinsic"),
+ None => ccx.sess().span_bug(foreign_item.span,
+ &format!("unknown intrinsic '{}'", name)),
};
fn one<T>(x: Vec<T>) -> T {
assert_eq!(x.len(), 1);
// MSVC's definition of the `rust_try` function. The exact implementation here
// is a little different than the GNU (standard) version below, not only because
// of the personality function but also because of the other fiddly bits about
-// SEH. LLVM also currently requires us to structure this a very particular way
-// as explained below.
+// SEH. LLVM also currently requires us to structure this in a very particular
+// way as explained below.
//
// Like with the GNU version we generate a shim wrapper
fn trans_msvc_try<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
return rust_try
}
+fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
+ span_err!(a, b, E0511, "{}", c);
+}
+
fn generic_simd_intrinsic<'blk, 'tcx, 'a>
(bcx: Block<'blk, 'tcx>,
name: &str,
emit_error!($msg, )
};
($msg: tt, $($fmt: tt)*) => {
- bcx.sess().span_err(call_info.span,
- &format!(concat!("invalid monomorphization of `{}` intrinsic: ",
- $msg),
- name, $($fmt)*));
+ span_invalid_monomorphization_error(
+ bcx.sess(), call_info.span,
+ &format!(concat!("invalid monomorphization of `{}` intrinsic: ",
+ $msg),
+ name, $($fmt)*));
}
}
macro_rules! require {
None => bcx.sess().span_bug(call_info.span,
"intrinsic call with unexpected argument shape"),
};
- let vector = consts::const_expr(bcx.ccx(), vector, tcx.mk_substs(substs), None).0;
+ let vector = match consts::const_expr(
+ bcx.ccx(),
+ vector,
+ tcx.mk_substs(substs),
+ None,
+ consts::TrueConst::Yes, // this should probably help simd error reporting
+ ) {
+ Ok((vector, _)) => vector,
+ Err(err) => bcx.sess().span_fatal(call_info.span, &err.description()),
+ };
let indices: Option<Vec<_>> = (0..n)
.map(|i| {
use middle::ty::MethodCall;
use syntax::ast;
+use syntax::attr;
use syntax::codemap::DUMMY_SP;
use syntax::ptr::P;
-use rustc_front::attr;
use rustc_front::visit;
use rustc_front::hir;
/// be generated once they are invoked with specific type parameters,
/// see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
pub fn trans_impl(ccx: &CrateContext,
- name: ast::Ident,
+ name: ast::Name,
impl_items: &[P<hir::ImplItem>],
generics: &hir::Generics,
id: ast::NodeId) {
impl_self,
rcvr_method));
- let mth_id = method_with_name(ccx, impl_did, mname);
- trans_fn_ref_with_substs(ccx, mth_id, ExprId(expr_id),
+ let mth = tcx.get_impl_method(impl_did, callee_substs, mname);
+ trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id),
param_substs,
- callee_substs)
+ mth.substs)
}
traits::VtableObject(ref data) => {
let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
}
}
-fn method_with_name(ccx: &CrateContext, impl_id: DefId, name: ast::Name)
- -> DefId {
- match ccx.impl_method_cache().borrow().get(&(impl_id, name)).cloned() {
- Some(m) => return m,
- None => {}
- }
-
- let impl_items = ccx.tcx().impl_items.borrow();
- let impl_items =
- impl_items.get(&impl_id)
- .expect("could not find impl while translating");
- let meth_did = impl_items.iter()
- .find(|&did| {
- ccx.tcx().impl_or_trait_item(did.def_id()).name() == name
- }).expect("could not find method while \
- translating");
-
- ccx.impl_method_cache().borrow_mut().insert((impl_id, name),
- meth_did.def_id());
- meth_did.def_id()
-}
-
fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
method_call: MethodCall,
self_expr: Option<&hir::Expr>,
item")
}
};
- let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
-
// create a concatenated set of substitutions which includes
// those from the impl and those from the method:
let callee_substs =
combine_impl_and_methods_tps(
bcx, MethodCallKey(method_call), vtable_impl.substs);
+ let mth = bcx.tcx().get_impl_method(impl_did, callee_substs, mname);
// translate the function
let datum = trans_fn_ref_with_substs(bcx.ccx(),
- mth_id,
+ mth.method.def_id,
MethodCallKey(method_call),
bcx.fcx.param_substs,
- callee_substs);
+ mth.substs);
Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
}
/// }
///
/// What is the value of `x` when `foo` is invoked with `T=SomeTrait`?
-/// The answer is that it it is a shim function generate by this
-/// routine:
+/// The answer is that it is a shim function generated by this routine:
///
/// fn shim(t: &SomeTrait) -> int {
/// // ... call t.get() virtually ...
C_uint(ccx, align)
].into_iter().chain(methods).collect();
- let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable");
+ let vtable_const = C_struct(ccx, &components, false);
+ let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
+ let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
vtable
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
- let impl_method_def_id = method_with_name(ccx, impl_id, name);
- let impl_method_type = match tcx.impl_or_trait_item(impl_method_def_id) {
- ty::MethodTraitItem(m) => m,
- _ => ccx.sess().bug("should be a method, not other assoc item"),
- };
+ let mth = tcx.get_impl_method(impl_id, substs.clone(), name);
- debug!("emit_vtable_methods: impl_method_type={:?}",
- impl_method_type);
+ debug!("emit_vtable_methods: mth={:?}", mth);
// If this is a default method, it's possible that it
// relies on where clauses that do not hold for this
// particular set of type parameters. Note that this
// method could then never be called, so we do not want to
// try and trans it, in that case. Issue #23435.
- if tcx.provided_source(impl_method_def_id).is_some() {
- let predicates = impl_method_type.predicates.predicates.subst(tcx, &substs);
+ if mth.is_provided {
+ let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
debug!("emit_vtable_methods: predicates do not hold");
return nullptr;
}
trans_fn_ref_with_substs(ccx,
- impl_method_def_id,
+ mth.method.def_id,
ExprId(0),
param_substs,
- substs.clone()).val
+ mth.substs).val
})
.collect()
}
fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
-> &'tcx ty::BareFnTy<'tcx> {
let mut inputs = method_ty.sig.0.inputs.clone();
- inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(hir::TyI8));
+ inputs[0] = tcx.mk_mut_ptr(tcx.mk_mach_int(ast::TyI8));
tcx.mk_bare_fn(ty::BareFnTy {
unsafety: method_ty.unsafety,
use rustc::front::map as hir_map;
use rustc_front::hir;
-use rustc_front::attr;
use syntax::abi;
use syntax::ast;
+use syntax::attr;
use std::hash::{Hasher, Hash, SipHasher};
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_id: DefId,
psubsts: &'tcx subst::Substs<'tcx>,
ref_id: Option<ast::NodeId>)
- -> (ValueRef, Ty<'tcx>, bool) {
+ -> (ValueRef, Ty<'tcx>, bool) {
debug!("monomorphic_fn(\
fn_id={:?}, \
real_substs={:?}, \
assert!(!psubsts.types.needs_infer() && !psubsts.types.has_param_types());
+ // we can only monomorphize things in this crate (or inlined into it)
+ let fn_node_id = ccx.tcx().map.as_local_node_id(fn_id).unwrap();
+
let _icx = push_ctxt("monomorphic_fn");
let hash_id = MonoId {
let map_node = session::expect(
ccx.sess(),
- ccx.tcx().map.find(fn_id.node),
+ ccx.tcx().map.find(fn_node_id),
|| {
format!("while monomorphizing {:?}, couldn't find it in \
the item map (may have attempted to monomorphize \
});
if let hir_map::NodeForeignItem(_) = map_node {
- let abi = ccx.tcx().map.get_foreign_abi(fn_id.node);
+ let abi = ccx.tcx().map.get_foreign_abi(fn_node_id);
if abi != abi::RustIntrinsic && abi != abi::PlatformIntrinsic {
// Foreign externs don't have to be monomorphized.
- return (get_item_val(ccx, fn_id.node), mono_ty, true);
+ return (get_item_val(ccx, fn_node_id), mono_ty, true);
}
}
Some(&d) => d, None => 0
};
+ debug!("monomorphic_fn: depth for fn_id={:?} is {:?}", fn_id, depth+1);
+
// Random cut-off -- code that needs to instantiate the same function
// recursively more than thirty times can probably safely be assumed
// to be causing an infinite expansion.
if depth > ccx.sess().recursion_limit.get() {
- ccx.sess().span_fatal(ccx.tcx().map.span(fn_id.node),
+ ccx.sess().span_fatal(ccx.tcx().map.span(fn_node_id),
"reached the recursion limit during monomorphization");
}
mono_ty.hash(&mut state);
hash = format!("h{}", state.finish());
- ccx.tcx().map.with_path(fn_id.node, |path| {
- exported_name(path, &hash[..])
- })
+ let path = ccx.tcx().map.def_path_from_id(fn_node_id);
+ exported_name(path, &hash[..])
};
debug!("monomorphize_fn mangled to {}", s);
let mut hash_id = Some(hash_id);
let mut mk_lldecl = |abi: abi::Abi| {
let lldecl = if abi != abi::Rust {
- foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..])
+ foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s)
} else {
// FIXME(nagisa): perhaps needs a more fine grained selection? See
// setup_lldecl below.
ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
lldecl
};
- let setup_lldecl = |lldecl, attrs: &[hir::Attribute]| {
+ let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| {
base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
attributes::from_fn_attrs(ccx, attrs, lldecl);
if needs_body {
if abi != abi::Rust {
foreign::trans_rust_fn_with_foreign_abi(
- ccx, &**decl, &**body, &[], d, psubsts, fn_id.node,
+ ccx, &**decl, &**body, &[], d, psubsts, fn_node_id,
Some(&hash[..]));
} else {
- trans_fn(ccx, &**decl, &**body, d, psubsts, fn_id.node, &[]);
+ trans_fn(ccx, &**decl, &**body, d, psubsts, fn_node_id, &[]);
}
}
}
}
hir_map::NodeVariant(v) => {
- let variant = inlined_variant_def(ccx, fn_id.node);
- assert_eq!(v.node.name.name, variant.name);
+ let variant = inlined_variant_def(ccx, fn_node_id);
+ assert_eq!(v.node.name, variant.name);
let d = mk_lldecl(abi::Rust);
attributes::inline(d, attributes::InlineAttr::Hint);
- trans_enum_variant(ccx, fn_id.node, variant.disr_val, psubsts, d);
+ trans_enum_variant(ccx, fn_node_id, variant.disr_val, psubsts, d);
d
}
hir_map::NodeImplItem(impl_item) => {
hir_map::NodeStructCtor(struct_def) => {
let d = mk_lldecl(abi::Rust);
attributes::inline(d, attributes::InlineAttr::Hint);
+ if struct_def.is_struct() {
+ panic!("ast-mapped struct didn't have a ctor id")
+ }
base::trans_tuple_struct(ccx,
- struct_def.ctor_id.expect("ast-mapped tuple struct \
- didn't have a ctor id"),
+ struct_def.id(),
psubsts,
d);
d
hir_map::NodeTyParam(..) |
hir_map::NodeExpr(..) |
hir_map::NodeStmt(..) |
- hir_map::NodeArg(..) |
hir_map::NodeBlock(..) |
hir_map::NodePat(..) |
hir_map::NodeLocal(..) => {
use rustc_front::hir;
+use syntax::ast;
use syntax::parse::token::InternedString;
#[derive(Copy, Clone)]
// Handle the "..." case (returns a slice since strings are always unsized):
if let hir::ExprLit(ref lit) = content_expr.node {
- if let hir::LitStr(ref s, _) = lit.node {
+ if let ast::LitStr(ref s, _) = lit.node {
let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
bcx = trans_lit_str(bcx,
content_expr,
match content_expr.node {
hir::ExprLit(ref lit) => {
match lit.node {
- hir::LitStr(ref s, _) => {
+ ast::LitStr(ref s, _) => {
match dest {
Ignore => return bcx,
SaveIn(lldest) => {
match content_expr.node {
hir::ExprLit(ref lit) => {
match lit.node {
- hir::LitStr(ref s, _) => s.len(),
+ ast::LitStr(ref s, _) => s.len(),
_ => {
bcx.tcx().sess.span_bug(content_expr.span,
"unexpected evec content")
use trans::context::CrateContext;
use util::nodemap::FnvHashMap;
-use rustc_front::hir;
+use syntax::ast;
use std::ffi::CString;
use std::mem;
}
}
- pub fn int_from_ty(ccx: &CrateContext, t: hir::IntTy) -> Type {
+ pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
match t {
- hir::TyIs => ccx.int_type(),
- hir::TyI8 => Type::i8(ccx),
- hir::TyI16 => Type::i16(ccx),
- hir::TyI32 => Type::i32(ccx),
- hir::TyI64 => Type::i64(ccx)
+ ast::TyIs => ccx.int_type(),
+ ast::TyI8 => Type::i8(ccx),
+ ast::TyI16 => Type::i16(ccx),
+ ast::TyI32 => Type::i32(ccx),
+ ast::TyI64 => Type::i64(ccx)
}
}
- pub fn uint_from_ty(ccx: &CrateContext, t: hir::UintTy) -> Type {
+ pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
match t {
- hir::TyUs => ccx.int_type(),
- hir::TyU8 => Type::i8(ccx),
- hir::TyU16 => Type::i16(ccx),
- hir::TyU32 => Type::i32(ccx),
- hir::TyU64 => Type::i64(ccx)
+ ast::TyUs => ccx.int_type(),
+ ast::TyU8 => Type::i8(ccx),
+ ast::TyU16 => Type::i16(ccx),
+ ast::TyU32 => Type::i32(ccx),
+ ast::TyU64 => Type::i64(ccx)
}
}
- pub fn float_from_ty(ccx: &CrateContext, t: hir::FloatTy) -> Type {
+ pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
match t {
- hir::TyF32 => Type::f32(ccx),
- hir::TyF64 => Type::f64(ccx),
+ ast::TyF32 => Type::f32(ccx),
+ ast::TyF64 => Type::f64(ccx),
}
}
use trans::type_::Type;
use syntax::abi;
-use rustc_front::hir;
+use syntax::ast;
// LLVM doesn't like objects that are too big. Issue #17913
fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let repr = adt::represent_type(cx, t);
// Unboxed closures can have substitutions in all spaces
// inherited from their environment, so we use entire
- // contents of the VecPerParamSpace to to construct the llvm
+ // contents of the VecPerParamSpace to construct the llvm
// name
adt::incomplete_type_of(cx, &*repr, "closure")
}
let unsized_part = cx.tcx().struct_tail(ty);
let info_ty = match unsized_part.sty {
ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
- Type::uint_from_ty(cx, hir::TyUs)
+ Type::uint_from_ty(cx, ast::TyUs)
}
ty::TyTrait(_) => Type::vtable_ptr(cx),
_ => panic!("Unexpected type returned from \
use middle::const_eval::{self, ConstVal};
use middle::const_eval::EvalHint::UncheckedExprHint;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::resolve_lifetime as rl;
use middle::privacy::{AllPublic, LastMod};
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
use util::common::{ErrorReported, FN_OUTPUT_NAME};
use util::nodemap::FnvHashSet;
-use std::slice;
use syntax::{abi, ast};
use syntax::codemap::{Span, Pos};
use syntax::feature_gate::{GateIssue, emit_feature_err};
use rustc_front::print::pprust;
use rustc_front::hir;
-
+use rustc_back::slice;
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx>;
}
Some(&rl::DefLateBoundRegion(debruijn, id)) => {
- ty::ReLateBound(debruijn, ty::BrNamed(DefId::local(id), lifetime.name))
+ ty::ReLateBound(debruijn, ty::BrNamed(tcx.map.local_def_id(id), lifetime.name))
}
Some(&rl::DefEarlyBoundRegion(space, index, id)) => {
+ let def_id = tcx.map.local_def_id(id);
ty::ReEarlyBound(ty::EarlyBoundRegion {
- param_id: id,
+ def_id: def_id,
space: space,
index: index,
name: lifetime.name
Some(&rl::DefFreeRegion(scope, id)) => {
ty::ReFree(ty::FreeRegion {
scope: tcx.region_maps.item_extent(scope.node_id),
- bound_region: ty::BrNamed(DefId::local(id),
+ bound_region: ty::BrNamed(tcx.map.local_def_id(id),
lifetime.name)
})
}
{
let tcx = this.tcx();
- // If the type is parameterized by the this region, then replace this
+ // If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
let expected_num_region_params = decl_generics.regions.len(TypeSpace);
let tcx = this.tcx();
debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}, \
- types_provided={:?}, region_substs={:?}",
+ types_provided={:?}, region_substs={:?})",
decl_generics, self_ty, types_provided,
region_substs);
}
}
+ debug!("create_substs_for_ast_path(decl_generics={:?}, self_ty={:?}) -> {:?}",
+ decl_generics, self_ty, substs);
+
substs
}
let assoc_bindings: Vec<_> =
data.bindings.iter()
- .map(|b| ConvertedBinding { item_name: b.ident.name,
+ .map(|b| ConvertedBinding { item_name: b.name,
ty: ast_ty_to_ty(this, rscope, &*b.ty),
span: b.span })
.collect();
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
-> ty::PolyTraitRef<'tcx>
{
+ debug!("ast_path_to_poly_trait_ref(trait_segment={:?})", trait_segment);
// The trait reference introduces a binding level here, so
// we need to shift the `rscope`. It'd be nice if we could
// do away with this rscope stuff and work this knowledge
poly_projections.extend(converted_bindings);
}
+ debug!("ast_path_to_poly_trait_ref(trait_segment={:?}, projections={:?}) -> {:?}",
+ trait_segment, poly_projections, poly_trait_ref);
poly_trait_ref
}
object.principal_trait_ref_with_self_ty(tcx, tcx.types.err);
// ensure the super predicates and stop if we encountered an error
- if this.ensure_super_predicates(span, object.principal_def_id()).is_err() {
+ if this.ensure_super_predicates(span, principal.def_id()).is_err() {
+ return tcx.types.err;
+ }
+
+ // check that there are no gross object safety violations,
+ // most importantly, that the supertraits don't contain Self,
+ // to avoid ICE-s.
+ let object_safety_violations =
+ traits::astconv_object_safety_violations(tcx, principal.def_id());
+ if !object_safety_violations.is_empty() {
+ traits::report_object_safety_error(
+ tcx, span, principal.def_id(), object_safety_violations, false);
return tcx.types.err;
}
Ok(bounds[0].clone())
}
-// Create a type from a a path to an associated type.
+// Create a type from a path to an associated type.
// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C
// and item_segment is the path segment for D. We return a type and a def for
// the whole path.
(_, def::DefSelfTy(Some(trait_did), Some((impl_id, _)))) => {
// `Self` in an impl of a trait - we have a concrete self type and a
// trait reference.
- let trait_ref = tcx.impl_trait_ref(DefId::local(impl_id)).unwrap();
+ let trait_ref = tcx.impl_trait_ref(tcx.map.local_def_id(impl_id)).unwrap();
let trait_ref = if let Some(free_substs) = this.get_free_substs() {
trait_ref.subst(tcx, free_substs)
} else {
}
}
(&ty::TyParam(_), def::DefSelfTy(Some(trait_did), None)) => {
- assert_eq!(trait_did.krate, LOCAL_CRATE);
+ let trait_node_id = tcx.map.as_local_node_id(trait_did).unwrap();
match find_bound_for_assoc_item(this,
- trait_did.node,
+ trait_node_id,
token::special_idents::type_self.name,
assoc_name,
span) {
}
}
(&ty::TyParam(_), def::DefTyParam(_, _, param_did, param_name)) => {
- assert_eq!(param_did.krate, LOCAL_CRATE);
+ let param_node_id = tcx.map.as_local_node_id(param_did).unwrap();
match find_bound_for_assoc_item(this,
- param_did.node,
+ param_node_id,
param_name,
assoc_name,
span) {
let trait_did = bound.0.def_id;
let ty = this.projected_ty_from_poly_trait_ref(span, bound, assoc_name);
- let item_did = if trait_did.is_local() {
+ let item_did = if let Some(trait_id) = tcx.map.as_local_node_id(trait_did) {
// `ty::trait_items` used below requires information generated
// by type collection, which may be in progress at this point.
- match tcx.map.expect_item(trait_did.node).node {
+ match tcx.map.expect_item(trait_id).node {
hir::ItemTrait(_, _, _, ref trait_items) => {
let item = trait_items.iter()
- .find(|i| i.ident.name == assoc_name)
+ .find(|i| i.name == assoc_name)
.expect("missing associated type");
- DefId::local(item.id)
+ tcx.map.local_def_id(item.id)
}
_ => unreachable!()
}
// we don't have the trait information around, which is just sad.
if !base_segments.is_empty() {
+ let id_node = tcx.map.as_local_node_id(id).unwrap();
span_err!(tcx.sess,
span,
E0247,
"found module name used as a type: {}",
- tcx.map.node_to_string(id.node));
+ tcx.map.node_to_user_string(id_node));
return this.tcx().types.err;
}
prim_ty_to_ty(tcx, base_segments, prim_ty)
}
_ => {
- let node = def.def_id().node;
+ let id_node = tcx.map.as_local_node_id(def.def_id()).unwrap();
span_err!(tcx.sess, span, E0248,
"found value `{}` used as a type",
- tcx.map.path_to_string(node));
+ tcx.map.path_to_string(id_node));
return this.tcx().types.err;
}
}
} else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
// Create some fake resolution that can't possibly be a type.
def::PathResolution {
- base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)),
+ base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
}
hir::TyFixedLengthVec(ref ty, ref e) => {
let hint = UncheckedExprHint(tcx.types.usize);
- match const_eval::eval_const_expr_partial(tcx, &e, hint) {
+ match const_eval::eval_const_expr_partial(tcx, &e, hint, None) {
Ok(r) => {
match r {
ConstVal::Int(i) =>
}
}
Err(ref r) => {
- let subspan =
- ast_ty.span.lo <= r.span.lo && r.span.hi <= ast_ty.span.hi;
span_err!(tcx.sess, r.span, E0250,
"array length constant evaluation error: {}",
r.description());
- if !subspan {
+ if !ast_ty.span.contains(r.span) {
span_note!(tcx.sess, ast_ty.span, "for array length here")
}
this.tcx().types.err
}
}
hir::TyTypeof(ref _e) => {
- tcx.sess.span_bug(ast_ty.span, "typeof is reserved but unimplemented");
+ span_err!(tcx.sess, ast_ty.span, E0516,
+ "`typeof` is a reserved keyword but unimplemented");
+ tcx.types.err
}
hir::TyInfer => {
// TyInfer also appears as the type of arguments or return
// except according to those terms.
use middle::def;
-use middle::def_id::DefId;
use middle::infer;
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
use middle::pat_util::pat_is_resolved_const;
use std::cmp;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax::ast;
+use syntax::ext::mtwt;
use syntax::codemap::{Span, Spanned};
use syntax::ptr::P;
// They can denote both statically and dynamically sized byte arrays
let mut pat_ty = expr_ty;
if let hir::ExprLit(ref lt) = lt.node {
- if let hir::LitByteStr(_) = lt.node {
+ if let ast::LitByteStr(_) = lt.node {
let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
if let ty::TyRef(_, mt) = expected_ty.sty {
if let ty::TySlice(_) = mt.ty.sty {
// if there are multiple arms, make sure they all agree on
// what the type of the binding `x` ought to be
- let canon_id = *pcx.map.get(&path.node).unwrap();
+ let canon_id = *pcx.map.get(&mtwt::resolve(path.node)).unwrap();
if canon_id != pat.id {
let ct = fcx.local_ty(pat.span, canon_id);
demand::eqtype(fcx, pat.span, ct, typ);
let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
d
} else if qself.position == 0 {
+ // This is just a sentinel for finish_resolving_def_to_ty.
+ let sentinel = fcx.tcx().map.local_def_id(ast::CRATE_NODE_ID);
def::PathResolution {
- // This is just a sentinel for finish_resolving_def_to_ty.
- base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)),
+ base_def: def::DefMod(sentinel),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
}
}
hir::PatRegion(ref inner, mutbl) => {
- let inner_ty = fcx.infcx().next_ty_var();
-
- let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
- let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
- let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
-
+ let expected = fcx.infcx().shallow_resolve(expected);
if check_dereferencable(pcx, pat.span, expected, &**inner) {
// `demand::subtype` would be good enough, but using
// `eqtype` turns out to be equally general. See (*)
// below for details.
- demand::eqtype(fcx, pat.span, expected, rptr_ty);
+
+ // Take region, inner-type from expected type if we
+ // can, to avoid creating needless variables. This
+ // also helps with the bad interactions of the given
+ // hack detailed in (*) below.
+ let (rptr_ty, inner_ty) = match expected.sty {
+ ty::TyRef(_, mt) if mt.mutbl == mutbl => {
+ (expected, mt.ty)
+ }
+ _ => {
+ let inner_ty = fcx.infcx().next_ty_var();
+ let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
+ let region = fcx.infcx().next_region_var(infer::PatternRegion(pat.span));
+ let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
+ demand::eqtype(fcx, pat.span, expected, rptr_ty);
+ (rptr_ty, inner_ty)
+ }
+ };
+
fcx.write_ty(pat.id, rptr_ty);
check_pat(pcx, &**inner, inner_ty);
} else {
let tcx = pcx.fcx.ccx.tcx;
let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
- let variant = match fcx.def_struct_variant(def) {
+ let variant = match fcx.def_struct_variant(def, path.span) {
Some((_, variant)) => variant,
None => {
let name = pprust::path_to_string(path);
// Typecheck each field.
for &Spanned { node: ref field, span } in fields {
- let field_ty = match used_fields.entry(field.ident.name) {
+ let field_ty = match used_fields.entry(field.name) {
Occupied(occupied) => {
span_err!(tcx.sess, span, E0025,
"field `{}` bound multiple times in the pattern",
- field.ident);
+ field.name);
span_note!(tcx.sess, *occupied.get(),
"field `{}` previously bound here",
- field.ident);
+ field.name);
tcx.types.err
}
Vacant(vacant) => {
vacant.insert(span);
- field_map.get(&field.ident.name)
+ field_map.get(&field.name)
.map(|f| pcx.fcx.field_ty(span, f, substs))
.unwrap_or_else(|| {
span_err!(tcx.sess, span, E0026,
"struct `{}` does not have a field named `{}`",
tcx.item_path_str(variant.did),
- field.ident);
+ field.name);
tcx.types.err
})
}
use super::write_call;
use CrateCtxt;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
use middle::infer;
use middle::ty::{self, LvaluePreference, Ty};
use syntax::codemap::Span;
use middle::ty::cast::{CastKind, CastTy};
use syntax::codemap::Span;
use rustc_front::hir;
-use rustc_front::hir::UintTy::TyU8;
+use syntax::ast;
+use syntax::ast::UintTy::TyU8;
/// Reifies a cast check to be checked once we have full type information for
(_, Int(Bool)) => Err(CastError::CastToBool),
// * -> Char
- (Int(U(hir::TyU8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
+ (Int(U(ast::TyU8)), Int(Char)) => Ok(CastKind::U8CharCast), // u8-char-cast
(_, Int(Char)) => Err(CastError::CastToChar),
// prim -> float,ptr
use super::{check_fn, Expectation, FnCtxt};
use astconv;
-use middle::def_id::DefId;
use middle::subst;
use middle::ty::{self, ToPolyTraitRef, Ty};
use std::cmp;
decl: &'tcx hir::FnDecl,
body: &'tcx hir::Block,
expected_sig: Option<ty::FnSig<'tcx>>) {
- let expr_def_id = DefId::local(expr.id);
+ let expr_def_id = fcx.tcx().map.local_def_id(expr.id);
debug!("check_closure opt_kind={:?} expected_sig={:?}",
opt_kind,
// Create a parameter environment that represents the implementation's
// method.
- let impl_param_env =
- ty::ParameterEnvironment::for_item(tcx, impl_m.def_id.node);
+ let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+ let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_m_node_id);
// Create mapping from impl to skolemized.
let impl_to_skol_substs = &impl_param_env.free_substs;
// Create a parameter environment that represents the implementation's
// method.
- let impl_param_env =
- ty::ParameterEnvironment::for_item(tcx, impl_c.def_id.node);
+ let impl_c_node_id = tcx.map.as_local_node_id(impl_c.def_id).unwrap();
+ let impl_param_env = ty::ParameterEnvironment::for_item(tcx, impl_c_node_id);
// Create mapping from impl to skolemized.
let impl_to_skol_substs = &impl_param_env.free_substs;
use check::regionck::{self, Rcx};
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::free_region::FreeRegionMap;
use middle::infer;
use middle::region;
drop_impl_ty: &ty::Ty<'tcx>,
self_type_did: DefId) -> Result<(), ()>
{
- assert!(drop_impl_did.is_local() && self_type_did.is_local());
+ let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap();
+ let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap();
// check that the impl type can be made to match the trait type.
- let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_did.node);
+ let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env), true);
let named_type = tcx.lookup_item_type(self_type_did).ty;
named_type, fresh_impl_self_ty) {
span_err!(tcx.sess, drop_impl_span, E0366,
"Implementations of Drop cannot be specialized");
- let item_span = tcx.map.span(self_type_did.node);
+ let item_span = tcx.map.span(self_type_node_id);
tcx.sess.span_note(item_span,
"Use same sequence of generic type and region \
parameters that is on the struct/enum definition");
}
let free_regions = FreeRegionMap::new();
- infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_did.node);
+ infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id);
Ok(())
}
// absent. So we report an error that the Drop impl injected a
// predicate that is not present on the struct definition.
- assert_eq!(self_type_did.krate, LOCAL_CRATE);
+ let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap();
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
for predicate in predicates {
// (We do not need to worry about deep analysis of type
// expressions etc because the Drop impls are already forced
- // to take on a structure that is roughly a alpha-renaming of
+ // to take on a structure that is roughly an alpha-renaming of
// the generic parameters of the item definition.)
// This path now just checks *all* predicates via the direct
// repeated `contains` calls.
if !assumptions_in_impl_context.contains(&predicate) {
- let item_span = tcx.map.span(self_type_did.node);
+ let item_span = tcx.map.span(self_type_node_id);
span_err!(tcx.sess, drop_impl_span, E0367,
"The requirement `{}` is added only by the Drop impl.", predicate);
tcx.sess.span_note(item_span,
///
/// ----
///
-/// The Drop Check Rule is the following:
+/// The simplified (*) Drop Check Rule is the following:
///
/// Let `v` be some value (either temporary or named) and 'a be some
/// lifetime (scope). If the type of `v` owns data of type `D`, where
///
-/// * (1.) `D` has a lifetime- or type-parametric Drop implementation, and
-/// * (2.) the structure of `D` can reach a reference of type `&'a _`, and
-/// * (3.) either:
-/// * (A.) the Drop impl for `D` instantiates `D` at 'a directly,
-/// i.e. `D<'a>`, or,
-/// * (B.) the Drop impl for `D` has some type parameter with a
-/// trait bound `T` where `T` is a trait that has at least
-/// one method,
+/// * (1.) `D` has a lifetime- or type-parametric Drop implementation,
+/// (where that `Drop` implementation does not opt-out of
+/// this check via the `unsafe_destructor_blind_to_params`
+/// attribute), and
+/// * (2.) the structure of `D` can reach a reference of type `&'a _`,
///
/// then 'a must strictly outlive the scope of v.
///
///
/// This function is meant to by applied to the type for every
/// expression in the program.
+///
+/// ----
+///
+/// (*) The qualifier "simplified" is attached to the above
+/// definition of the Drop Check Rule, because it is a simplification
+/// of the original Drop Check rule, which attempted to prove that
+/// some `Drop` implementations could not possibly access data even if
+/// it was technically reachable, due to parametricity.
+///
+/// However, (1.) parametricity on its own turned out to be a
+/// necessary but insufficient condition, and (2.) future changes to
+/// the language are expected to make it impossible to ensure that a
+/// `Drop` implementation is actually parametric with respect to any
+/// particular type parameter. (In particular, impl specialization is
+/// expected to break the needed parametricity property beyond
+/// repair.)
+///
+/// Therefore we have scaled back Drop-Check to a more conservative
+/// rule that does not attempt to deduce whether a `Drop`
+/// implementation could not possible access data of a given lifetime;
+/// instead Drop-Check now simply assumes that if a destructor has
+/// access (direct or indirect) to a lifetime parameter, then that
+/// lifetime must be forced to outlive that destructor's dynamic
+/// extent. We then provide the `unsafe_destructor_blind_to_params`
+/// attribute as a way for destructor implementations to opt-out of
+/// this conservative assumption (and thus assume the obligation of
+/// ensuring that they do not access data nor invoke methods of
+/// values that have been previously dropped).
+///
pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
typ: ty::Ty<'tcx>,
span: Span,
// borrowed data reachable via `typ` must outlive the parent
// of `scope`. This is handled below.
//
- // However, there is an important special case: by
- // parametricity, any generic type parameters have *no* trait
- // bounds in the Drop impl can not be used in any way (apart
- // from being dropped), and thus we can treat data borrowed
- // via such type parameters remains unreachable.
+ // However, there is an important special case: for any Drop
+ // impl that is tagged as "blind" to their parameters,
+ // we assume that data borrowed via such type parameters
+ // remains unreachable via that Drop impl.
+ //
+ // For example, consider:
+ //
+ // ```rust
+ // #[unsafe_destructor_blind_to_params]
+ // impl<T> Drop for Vec<T> { ... }
+ // ```
//
- // For example, consider `impl<T> Drop for Vec<T> { ... }`,
// which does have to be able to drop instances of `T`, but
// otherwise cannot read data from `T`.
//
// unbounded type parameter `T`, we must resume the recursive
// analysis on `T` (since it would be ignored by
// type_must_outlive).
- //
- // FIXME (pnkfelix): Long term, we could be smart and actually
- // feed which generic parameters can be ignored *into* `fn
- // type_must_outlive` (or some generalization thereof). But
- // for the short term, it probably covers most cases of
- // interest to just special case Drop impls where: (1.) there
- // are no generic lifetime parameters and (2.) *all* generic
- // type parameters are unbounded. If both conditions hold, we
- // simply skip the `type_must_outlive` call entirely (but
- // resume the recursive checking of the type-substructure).
if has_dtor_of_interest(tcx, ty) {
debug!("iterate_over_potentially_unsafe_regions_in_type \
{}ty: {} - is a dtorck type!",
use astconv::AstConv;
use intrinsics;
-use middle::def_id::DefId;
use middle::subst;
use middle::ty::FnSig;
use middle::ty::{self, Ty};
use std::collections::{HashMap};
use syntax::abi;
+use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use syntax::parse::token;
variadic: false,
}),
}));
- let i_ty = tcx.lookup_item_type(DefId::local(it.id));
+ let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id));
let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
if i_n_tps != n_tps {
span_err!(tcx.sess, it.span, E0094,
}
let tcx = ccx.tcx;
- let name = it.ident.name.as_str();
+ let name = it.name.as_str();
let (n_tps, inputs, output) = if name.starts_with("atomic_") {
let split : Vec<&str> = name.split('_').collect();
assert!(split.len() >= 2, "Atomic intrinsic not correct format");
};
let tcx = ccx.tcx;
- let i_ty = tcx.lookup_item_type(DefId::local(it.id));
+ let i_ty = tcx.lookup_item_type(tcx.map.local_def_id(it.id));
let i_n_tps = i_ty.generics.types.len(subst::FnSpace);
- let name = it.ident.name.as_str();
+ let name = it.name.as_str();
let (n_tps, inputs, output) = match &*name {
"simd_eq" | "simd_ne" | "simd_lt" | "simd_le" | "simd_gt" | "simd_ge" => {
},
// (The width we pass to LLVM doesn't concern the type checker.)
Integer(signed, bits, _llvm_width) => match (signed, bits, &t.sty) {
- (true, 8, &ty::TyInt(hir::IntTy::TyI8)) |
- (false, 8, &ty::TyUint(hir::UintTy::TyU8)) |
- (true, 16, &ty::TyInt(hir::IntTy::TyI16)) |
- (false, 16, &ty::TyUint(hir::UintTy::TyU16)) |
- (true, 32, &ty::TyInt(hir::IntTy::TyI32)) |
- (false, 32, &ty::TyUint(hir::UintTy::TyU32)) |
- (true, 64, &ty::TyInt(hir::IntTy::TyI64)) |
- (false, 64, &ty::TyUint(hir::UintTy::TyU64)) => {},
+ (true, 8, &ty::TyInt(ast::IntTy::TyI8)) |
+ (false, 8, &ty::TyUint(ast::UintTy::TyU8)) |
+ (true, 16, &ty::TyInt(ast::IntTy::TyI16)) |
+ (false, 16, &ty::TyUint(ast::UintTy::TyU16)) |
+ (true, 32, &ty::TyInt(ast::IntTy::TyI32)) |
+ (false, 32, &ty::TyUint(ast::UintTy::TyU32)) |
+ (true, 64, &ty::TyInt(ast::IntTy::TyI64)) |
+ (false, 64, &ty::TyUint(ast::UintTy::TyU64)) => {},
_ => simple_error(&format!("`{}`", t),
&format!("`{}{n}`",
if signed {"i"} else {"u"},
n = bits)),
},
Float(bits) => match (bits, &t.sty) {
- (32, &ty::TyFloat(hir::FloatTy::TyF32)) |
- (64, &ty::TyFloat(hir::FloatTy::TyF64)) => {},
+ (32, &ty::TyFloat(ast::FloatTy::TyF32)) |
+ (64, &ty::TyFloat(ast::FloatTy::TyF64)) => {},
_ => simple_error(&format!("`{}`", t),
&format!("`f{n}`", n = bits)),
},
// Unify the (adjusted) self type with what the method expects.
self.unify_receivers(self_ty, method_self_ty);
- // Add any trait/regions obligations specified on the method's type parameters.
- self.add_obligations(&pick, &all_substs, &method_predicates);
-
- // Create the final `MethodCallee`.
+ // Create the method type
let method_ty = pick.item.as_opt_method().unwrap();
let fty = self.tcx().mk_fn(None, self.tcx().mk_bare_fn(ty::BareFnTy {
sig: ty::Binder(method_sig),
unsafety: method_ty.fty.unsafety,
abi: method_ty.fty.abi.clone(),
}));
+
+ // Add any trait/regions obligations specified on the method's type parameters.
+ self.add_obligations(fty, &all_substs, &method_predicates);
+
+ // Create the final `MethodCallee`.
let callee = ty::MethodCallee {
def_id: pick.item.def_id(),
ty: fty,
substs: self.tcx().mk_substs(all_substs)
};
-
// If this is an `&mut self` method, bias the receiver
// expression towards mutability (this will switch
// e.g. `Deref` to `DerefMut` in overloaded derefs and so on).
}
fn add_obligations(&mut self,
- pick: &probe::Pick<'tcx>,
+ fty: Ty<'tcx>,
all_substs: &subst::Substs<'tcx>,
method_predicates: &ty::InstantiatedPredicates<'tcx>) {
- debug!("add_obligations: pick={:?} all_substs={:?} method_predicates={:?}",
- pick,
+ debug!("add_obligations: fty={:?} all_substs={:?} method_predicates={:?}",
+ fty,
all_substs,
method_predicates);
self.fcx.add_wf_bounds(
all_substs,
self.call_expr);
+
+ // the function type must also be well-formed (this is not
+ // implied by the substs being well-formed because of inherent
+ // impls and late-bound regions - see issue #28609).
+ self.fcx.register_wf_obligation(fty, self.span, traits::MiscObligation);
}
///////////////////////////////////////////////////////////////////////////
loop {
let last = exprs[exprs.len() - 1];
match last.node {
- hir::ExprParen(ref expr) |
hir::ExprField(ref expr, _) |
hir::ExprTupField(ref expr, _) |
hir::ExprIndex(ref expr, _) |
traits::ObligationCause::misc(span, fcx.body_id),
&method_bounds);
+ // Also register an obligation for the method type being well-formed.
+ fcx.register_wf_obligation(fty, span, traits::MiscObligation);
+
// FIXME(#18653) -- Try to resolve obligations, giving us more
// typing information, which can sometimes be needed to avoid
// pathological region inference failures.
let lang_def_id = self.tcx().lang_items.mut_ptr_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyInt(hir::TyI8) => {
+ ty::TyInt(ast::TyI8) => {
let lang_def_id = self.tcx().lang_items.i8_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyInt(hir::TyI16) => {
+ ty::TyInt(ast::TyI16) => {
let lang_def_id = self.tcx().lang_items.i16_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyInt(hir::TyI32) => {
+ ty::TyInt(ast::TyI32) => {
let lang_def_id = self.tcx().lang_items.i32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyInt(hir::TyI64) => {
+ ty::TyInt(ast::TyI64) => {
let lang_def_id = self.tcx().lang_items.i64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyInt(hir::TyIs) => {
+ ty::TyInt(ast::TyIs) => {
let lang_def_id = self.tcx().lang_items.isize_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyUint(hir::TyU8) => {
+ ty::TyUint(ast::TyU8) => {
let lang_def_id = self.tcx().lang_items.u8_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyUint(hir::TyU16) => {
+ ty::TyUint(ast::TyU16) => {
let lang_def_id = self.tcx().lang_items.u16_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyUint(hir::TyU32) => {
+ ty::TyUint(ast::TyU32) => {
let lang_def_id = self.tcx().lang_items.u32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyUint(hir::TyU64) => {
+ ty::TyUint(ast::TyU64) => {
let lang_def_id = self.tcx().lang_items.u64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyUint(hir::TyUs) => {
+ ty::TyUint(ast::TyUs) => {
let lang_def_id = self.tcx().lang_items.usize_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyFloat(hir::TyF32) => {
+ ty::TyFloat(ast::TyF32) => {
let lang_def_id = self.tcx().lang_items.f32_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
- ty::TyFloat(hir::TyF64) => {
+ ty::TyFloat(ast::TyF64) => {
let lang_def_id = self.tcx().lang_items.f64_impl();
self.assemble_inherent_impl_for_primitive(lang_def_id);
}
use astconv::AstConv;
use check::{self, FnCtxt};
+use front::map as hir_map;
use middle::ty::{self, Ty, ToPolyTraitRef, ToPredicate, HasTypeFlags};
use middle::def;
use middle::def_id::DefId;
use middle::subst::Substs;
use middle::traits::{Obligation, SelectionContext};
use metadata::{csearch, cstore, decoder};
+use util::nodemap::{FnvHashSet};
use syntax::ast;
use syntax::codemap::Span;
CandidateSource::ImplSource(impl_did) => {
// Provide the best span we can. Use the item, if local to crate, else
// the impl, if local to crate (item may be defaulted), else the call site.
- let item = impl_item(fcx.tcx(), impl_did, item_name).unwrap();
+ let item = impl_item(fcx.tcx(), impl_did, item_name)
+ .or_else(|| {
+ trait_item(
+ fcx.tcx(),
+ fcx.tcx().impl_trait_ref(impl_did).unwrap().def_id,
+ item_name
+ )
+ }).unwrap();
let impl_span = fcx.tcx().map.def_id_span(impl_did, span);
let item_span = fcx.tcx().map.def_id_span(item.def_id(), impl_span);
}
impl Ord for TraitInfo {
fn cmp(&self, other: &TraitInfo) -> Ordering {
- // accessible traits are more important/relevant than
- // inaccessible ones, local crates are more important than
- // remote ones (local: cnum == 0), and NodeIds just for
- // totality.
+ // local crates are more important than remote ones (local:
+ // cnum == 0), and otherwise we throw in the defid for totality
- let lhs = (other.def_id.krate, other.def_id.node);
- let rhs = (self.def_id.krate, self.def_id.node);
+ let lhs = (other.def_id.krate, other.def_id);
+ let rhs = (self.def_id.krate, self.def_id);
lhs.cmp(&rhs)
}
}
// Crate-local:
//
// meh.
- struct Visitor<'a> {
+ struct Visitor<'a, 'tcx:'a> {
+ map: &'a hir_map::Map<'tcx>,
traits: &'a mut AllTraitsVec,
}
- impl<'v, 'a> visit::Visitor<'v> for Visitor<'a> {
+ impl<'v, 'a, 'tcx> visit::Visitor<'v> for Visitor<'a, 'tcx> {
fn visit_item(&mut self, i: &'v hir::Item) {
match i.node {
hir::ItemTrait(..) => {
- self.traits.push(TraitInfo::new(DefId::local(i.id)));
+ let def_id = self.map.local_def_id(i.id);
+ self.traits.push(TraitInfo::new(def_id));
}
_ => {}
}
}
}
visit::walk_crate(&mut Visitor {
+ map: &ccx.tcx.map,
traits: &mut traits
}, ccx.tcx.map.krate());
// Cross-crate:
+ let mut external_mods = FnvHashSet();
fn handle_external_def(traits: &mut AllTraitsVec,
+ external_mods: &mut FnvHashSet<DefId>,
ccx: &CrateCtxt,
cstore: &cstore::CStore,
dl: decoder::DefLike) {
traits.push(TraitInfo::new(did));
}
decoder::DlDef(def::DefMod(did)) => {
+ if !external_mods.insert(did) {
+ return;
+ }
csearch::each_child_of_item(cstore, did, |dl, _, _| {
- handle_external_def(traits, ccx, cstore, dl)
+ handle_external_def(traits, external_mods,
+ ccx, cstore, dl)
})
}
_ => {}
let cstore = &ccx.tcx.sess.cstore;
cstore.iter_crate_data(|cnum, _| {
csearch::each_top_level_item_of_crate(cstore, cnum, |dl, _, _| {
- handle_external_def(&mut traits, ccx, cstore, dl)
+ handle_external_def(&mut traits,
+ &mut external_mods,
+ ccx, cstore, dl)
})
});
use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
use check::_match::pat_ctxt;
use fmt_macros::{Parser, Piece, Position};
+use metadata::cstore::LOCAL_CRATE;
use middle::astconv_util::prohibit_type_params;
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::infer;
use middle::infer::type_variable;
use middle::pat_util::{self, pat_id_map};
use std::cell::{Cell, Ref, RefCell};
use std::collections::{HashSet};
use std::mem::replace;
-use std::slice;
use syntax::abi;
use syntax::ast;
-use syntax::codemap::{self, Span};
+use syntax::attr;
+use syntax::attr::AttrMetaMethods;
+use syntax::codemap::{self, Span, Spanned};
use syntax::owned_slice::OwnedSlice;
use syntax::parse::token::{self, InternedString};
use syntax::ptr::P;
use rustc_front::visit::{self, Visitor};
use rustc_front::hir;
use rustc_front::hir::Visibility;
-use rustc_front::attr;
-use rustc_front::attr::AttrMetaMethods;
use rustc_front::hir::{Item, ItemImpl};
use rustc_front::print::pprust;
+use rustc_back::slice;
mod assoc;
pub mod dropck;
(unsafety, blk.id, self.unsafe_push_count.checked_sub(1).unwrap()),
hir::UnsafeBlock(..) =>
(hir::Unsafety::Unsafe, blk.id, self.unsafe_push_count),
- hir::DefaultBlock =>
+ hir::DefaultBlock | hir::PushUnstableBlock | hir:: PopUnstableBlock =>
(unsafety, self.def, self.unsafe_push_count),
};
UnsafetyState{ def: def,
hir::TyFixedLengthVec(_, ref expr) => {
check_const_in_type(self.ccx, &**expr, self.ccx.tcx.types.usize);
}
+ hir::TyBareFn(ref function_declaration) => {
+ visit::walk_fn_decl_nopat(self, &function_declaration.decl);
+ walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
+ return
+ }
_ => {}
}
self.visit_ty(&**ty);
check_expr_with_hint(self.fcx, &**count_expr, self.fcx.tcx().types.usize);
}
+ hir::TyBareFn(ref function_declaration) => {
+ visit::walk_fn_decl_nopat(self, &function_declaration.decl);
+ walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
+ }
_ => visit::walk_ty(self, t)
}
}
check_representable(tcx, span, id, "struct");
- if tcx.lookup_simd(DefId::local(id)) {
+ if tcx.lookup_simd(ccx.tcx.map.local_def_id(id)) {
check_simd(tcx, span, id);
}
}
pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
- debug!("check_item_type(it.id={}, it.ident={})",
+ debug!("check_item_type(it.id={}, it.name={})",
it.id,
- ccx.tcx.item_path_str(DefId::local(it.id)));
+ ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id)));
let _indenter = indenter();
match it.node {
// Consts can play a role in type-checking, so they are included here.
}
hir::ItemFn(..) => {} // entirely within check_item_body
hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
- debug!("ItemImpl {} with id {}", it.ident, it.id);
- match ccx.tcx.impl_trait_ref(DefId::local(it.id)) {
+ debug!("ItemImpl {} with id {}", it.name, it.id);
+ match ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(it.id)) {
Some(impl_trait_ref) => {
check_impl_items_against_trait(ccx,
it.span,
}
} else {
for item in &m.items {
- let pty = ccx.tcx.lookup_item_type(DefId::local(item.id));
+ let pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(item.id));
if !pty.generics.types.is_empty() {
span_err!(ccx.tcx.sess, item.span, E0044,
"foreign items may not have type parameters");
}
pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
- debug!("check_item_body(it.id={}, it.ident={})",
+ debug!("check_item_body(it.id={}, it.name={})",
it.id,
- ccx.tcx.item_path_str(DefId::local(it.id)));
+ ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(it.id)));
let _indenter = indenter();
match it.node {
hir::ItemFn(ref decl, _, _, _, _, ref body) => {
- let fn_pty = ccx.tcx.lookup_item_type(DefId::local(it.id));
+ let fn_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id));
let param_env = ParameterEnvironment::for_item(ccx.tcx, it.id);
check_bare_fn(ccx, &**decl, &**body, it.id, it.span, fn_pty.ty, param_env);
}
hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
- debug!("ItemImpl {} with id {}", it.ident, it.id);
+ debug!("ItemImpl {} with id {}", it.name, it.id);
- let impl_pty = ccx.tcx.lookup_item_type(DefId::local(it.id));
+ let impl_pty = ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(it.id));
for impl_item in impl_items {
match impl_item.node {
}
}
hir::ItemTrait(_, _, _, ref trait_items) => {
- let trait_def = ccx.tcx.lookup_trait_def(DefId::local(it.id));
+ let trait_def = ccx.tcx.lookup_trait_def(ccx.tcx.map.local_def_id(it.id));
for trait_item in trait_items {
match trait_item.node {
hir::ConstTraitItem(_, Some(ref expr)) => {
Position::ArgumentNamed(s) if s == "Self" => (),
// So is `{A}` if A is a type parameter
Position::ArgumentNamed(s) => match types.iter().find(|t| {
- t.ident.name == s
+ t.name.as_str() == s
}) {
Some(_) => (),
None => {
span_err!(ccx.tcx.sess, attr.span, E0230,
"there is no type parameter \
{} on trait {}",
- s, item.ident);
+ s, item.name);
}
},
// `{:1}` and `{}` are not to be used
// Check existing impl methods to see if they are both present in trait
// and compatible with trait signature
for impl_item in impl_items {
- let ty_impl_item = ccx.tcx.impl_or_trait_item(DefId::local(impl_item.id));
+ let ty_impl_item = ccx.tcx.impl_or_trait_item(ccx.tcx.map.local_def_id(impl_item.id));
let ty_trait_item = trait_items.iter()
.find(|ac| ac.name() == ty_impl_item.name())
.unwrap_or_else(|| {
// Check for missing items from trait
let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id);
- let associated_consts = tcx.associated_consts(impl_trait_ref.def_id);
let mut missing_items = Vec::new();
let mut invalidated_items = Vec::new();
let associated_type_overridden = overridden_associated_type.is_some();
let is_implemented = impl_items.iter().any(|ii| {
match ii.node {
hir::ConstImplItem(..) => {
- ii.ident.name == associated_const.name
+ ii.name == associated_const.name
}
_ => false,
}
});
- let is_provided =
- associated_consts.iter().any(|ac| ac.default.is_some() &&
- ac.name == associated_const.name);
+ let is_provided = associated_const.has_value;
+
if !is_implemented {
if !is_provided {
missing_items.push(associated_const.name);
impl_items.iter().any(|ii| {
match ii.node {
hir::MethodImplItem(..) => {
- ii.ident.name == trait_method.name
+ ii.name == trait_method.name
}
_ => false,
}
let is_implemented = impl_items.iter().any(|ii| {
match ii.node {
hir::TypeImplItem(_) => {
- ii.ident.name == associated_type.name
+ ii.name == associated_type.name
}
_ => false,
}
span_err!(tcx.sess, invalidator.span, E0399,
"the following trait items need to be reimplemented \
as `{}` was overridden: `{}`",
- invalidator.ident,
+ invalidator.name,
invalidated_items.iter()
.map(|name| name.to_string())
.collect::<Vec<_>>().join("`, `"))
match self.inh.locals.borrow().get(&nid) {
Some(&t) => t,
None => {
- self.tcx().sess.span_err(
- span,
- &format!("no type for local variable {}", nid));
+ span_err!(self.tcx().sess, span, E0513,
+ "no type for local variable {}",
+ nid);
self.tcx().types.err
}
}
/// Return the dict-like variant corresponding to a given `Def`.
pub fn def_struct_variant(&self,
- def: def::Def)
+ def: def::Def,
+ span: Span)
-> Option<(ty::AdtDef<'tcx>, ty::VariantDef<'tcx>)>
{
let (adt, variant) = match def {
_ => return None
};
- if let ty::VariantKind::Dict = variant.kind() {
+ let var_kind = variant.kind();
+ if var_kind == ty::VariantKind::Struct {
Some((adt, variant))
- } else {
- None
- }
- }
+ } else if var_kind == ty::VariantKind::Unit {
+ if !self.tcx().sess.features.borrow().braced_empty_structs {
+ self.tcx().sess.span_err(span, "empty structs and enum variants \
+ with braces are unstable");
+ fileline_help!(self.tcx().sess, span, "add #![feature(braced_empty_structs)] to \
+ the crate features to enable");
+ }
+ Some((adt, variant))
+ } else {
+ None
+ }
+ }
pub fn write_nil(&self, node_id: ast::NodeId) {
self.write_ty(node_id, self.tcx().mk_nil());
pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
let t = ast_ty_to_ty(self, self, ast_t);
-
- // Generally speaking, we must check that types entered by the
- // user are well-formed. This is not true for `_`, since those
- // types are generated by inference. Now, you might think that
- // we could as well generate a WF obligation -- but
- // unfortunately that breaks code like `foo as *const _`,
- // because those type variables wind up being unconstrained
- // until very late. Nasty. Probably it'd be best to refactor
- // that code path, but that's tricky because of
- // defaults. Argh!
- match ast_t.node {
- hir::TyInfer => { }
- _ => { self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); }
- }
-
+ self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
t
}
// There is a possibility that this algorithm will have to run an arbitrary number of times
// to terminate so we bound it by the compiler's recursion limit.
- for _ in (0..self.tcx().sess.recursion_limit.get()) {
+ for _ in 0..self.tcx().sess.recursion_limit.get() {
// First we try to solve all obligations, it is possible that the last iteration
// has made it possible to make more progress.
self.select_obligations_where_possible();
}
// If there are no more fallbacks to apply at this point we have applied all possible
- // defaults and type inference will procede as normal.
+ // defaults and type inference will proceed as normal.
if unbound_tyvars.is_empty() {
break;
}
.unwrap_or(type_variable::Default {
ty: self.infcx().next_ty_var(),
origin_span: codemap::DUMMY_SP,
- def_id: DefId::local(0) // what do I put here?
+ def_id: self.tcx().map.local_def_id(0) // what do I put here?
});
// This is to ensure that we elimnate any non-determinism from the error
{
match method {
Some(method) => {
- // extract method method return type, which will be &T;
+ // extract method return type, which will be &T;
// all LB regions should have been instantiated during method lookup
let ret_ty = method.ty.fn_ret();
let ret_ty = fcx.tcx().no_late_bound_regions(&ret_ty).unwrap().unwrap();
// First, try built-in indexing.
match (adjusted_ty.builtin_index(), &index_ty.sty) {
- (Some(ty), &ty::TyUint(hir::TyUs)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
+ (Some(ty), &ty::TyUint(ast::TyUs)) | (Some(ty), &ty::TyInfer(ty::IntVar(_))) => {
debug!("try_index_step: success, using built-in indexing");
// If we had `[T; N]`, we should've caught it before unsizing to `[T]`.
assert!(!unsize);
let arg_ty = structurally_resolved_type(fcx, arg.span,
fcx.expr_ty(&**arg));
match arg_ty.sty {
- ty::TyFloat(hir::TyF32) => {
+ ty::TyFloat(ast::TyF32) => {
fcx.type_error_message(arg.span,
|t| {
format!("can't pass an {} to variadic \
function, cast to c_double", t)
}, arg_ty, None);
}
- ty::TyInt(hir::TyI8) | ty::TyInt(hir::TyI16) | ty::TyBool => {
+ ty::TyInt(ast::TyI8) | ty::TyInt(ast::TyI16) | ty::TyBool => {
fcx.type_error_message(arg.span, |t| {
format!("can't pass {} to variadic \
function, cast to c_int",
t)
}, arg_ty, None);
}
- ty::TyUint(hir::TyU8) | ty::TyUint(hir::TyU16) => {
+ ty::TyUint(ast::TyU8) | ty::TyUint(ast::TyU16) => {
fcx.type_error_message(arg.span, |t| {
format!("can't pass {} to variadic \
function, cast to c_uint",
// AST fragment checking
fn check_lit<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- lit: &hir::Lit,
+ lit: &ast::Lit,
expected: Expectation<'tcx>)
-> Ty<'tcx>
{
let tcx = fcx.ccx.tcx;
match lit.node {
- hir::LitStr(..) => tcx.mk_static_str(),
- hir::LitByteStr(ref v) => {
+ ast::LitStr(..) => tcx.mk_static_str(),
+ ast::LitByteStr(ref v) => {
tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
tcx.mk_array(tcx.types.u8, v.len()))
}
- hir::LitByte(_) => tcx.types.u8,
- hir::LitChar(_) => tcx.types.char,
- hir::LitInt(_, hir::SignedIntLit(t, _)) => tcx.mk_mach_int(t),
- hir::LitInt(_, hir::UnsignedIntLit(t)) => tcx.mk_mach_uint(t),
- hir::LitInt(_, hir::UnsuffixedIntLit(_)) => {
+ ast::LitByte(_) => tcx.types.u8,
+ ast::LitChar(_) => tcx.types.char,
+ ast::LitInt(_, ast::SignedIntLit(t, _)) => tcx.mk_mach_int(t),
+ ast::LitInt(_, ast::UnsignedIntLit(t)) => tcx.mk_mach_uint(t),
+ ast::LitInt(_, ast::UnsuffixedIntLit(_)) => {
let opt_ty = expected.to_option(fcx).and_then(|ty| {
match ty.sty {
ty::TyInt(_) | ty::TyUint(_) => Some(ty),
opt_ty.unwrap_or_else(
|| tcx.mk_int_var(fcx.infcx().next_int_var_id()))
}
- hir::LitFloat(_, t) => tcx.mk_mach_float(t),
- hir::LitFloatUnsuffixed(_) => {
+ ast::LitFloat(_, t) => tcx.mk_mach_float(t),
+ ast::LitFloatUnsuffixed(_) => {
let opt_ty = expected.to_option(fcx).and_then(|ty| {
match ty.sty {
ty::TyFloat(_) => Some(ty),
opt_ty.unwrap_or_else(
|| tcx.mk_float_var(fcx.infcx().next_float_var_id()))
}
- hir::LitBool(_) => tcx.types.bool
+ ast::LitBool(_) => tcx.types.bool
}
}
// Checks a method call.
fn check_method_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
expr: &'tcx hir::Expr,
- method_name: hir::SpannedIdent,
+ method_name: Spanned<ast::Name>,
args: &'tcx [P<hir::Expr>],
tps: &[P<hir::Ty>],
expected: Expectation<'tcx>,
let tps = tps.iter().map(|ast_ty| fcx.to_ty(&**ast_ty)).collect::<Vec<_>>();
let fn_ty = match method::lookup(fcx,
method_name.span,
- method_name.node.name,
+ method_name.node,
expr_t,
tps,
expr,
}
Err(error) => {
method::report_error(fcx, method_name.span, expr_t,
- method_name.node.name, Some(rcvr), error);
+ method_name.node, Some(rcvr), error);
fcx.write_error(expr.id);
fcx.tcx().types.err
}
expr: &'tcx hir::Expr,
lvalue_pref: LvaluePreference,
base: &'tcx hir::Expr,
- field: &hir::SpannedIdent) {
+ field: &Spanned<ast::Name>) {
let tcx = fcx.ccx.tcx;
check_expr_with_lvalue_pref(fcx, base, lvalue_pref);
let expr_t = structurally_resolved_type(fcx, expr.span,
ty::TyStruct(base_def, substs) => {
debug!("struct named {:?}", base_t);
base_def.struct_variant()
- .find_field_named(field.node.name)
+ .find_field_named(field.node)
.map(|f| fcx.field_ty(expr.span, f, substs))
}
_ => None
None => {}
}
- if method::exists(fcx, field.span, field.node.name, expr_t, expr.id) {
+ if method::exists(fcx, field.span, field.node, expr_t, expr.id) {
fcx.type_error_message(
field.span,
|actual| {
// displays hints about the closest matches in field names
fn suggest_field_names<'tcx>(variant: ty::VariantDef<'tcx>,
- field: &hir::SpannedIdent,
+ field: &Spanned<ast::Name>,
tcx: &ty::ctxt<'tcx>,
skip : Vec<InternedString>) {
- let name = field.node.name.as_str();
+ let name = field.node.as_str();
// only find fits with at least one matching letter
let mut best_dist = name.len();
let mut best = None;
field: &hir::Field,
skip_fields: &[hir::Field]) {
fcx.type_error_message(
- field.ident.span,
+ field.name.span,
|actual| if let ty::TyEnum(..) = ty.sty {
format!("struct variant `{}::{}` has no field named `{}`",
- actual, variant.name.as_str(), field.ident.node)
+ actual, variant.name.as_str(), field.name.node)
} else {
format!("structure `{}` has no field named `{}`",
- actual, field.ident.node)
+ actual, field.name.node)
},
ty,
None);
// prevent all specified fields from being suggested
- let skip_fields = skip_fields.iter().map(|ref x| x.ident.node.name.as_str());
- suggest_field_names(variant, &field.ident, fcx.tcx(), skip_fields.collect());
+ let skip_fields = skip_fields.iter().map(|ref x| x.name.node.as_str());
+ suggest_field_names(variant, &field.name, fcx.tcx(), skip_fields.collect());
}
-
fn check_expr_struct_fields<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
adt_ty: Ty<'tcx>,
span: Span,
for field in ast_fields {
let expected_field_type;
- if let Some(v_field) = remaining_fields.remove(&field.ident.node.name) {
+ if let Some(v_field) = remaining_fields.remove(&field.name.node) {
expected_field_type = fcx.field_ty(field.span, v_field, substs);
} else {
error_happened = true;
expected_field_type = tcx.types.err;
- if let Some(_) = variant.find_field_named(field.ident.node.name) {
- span_err!(fcx.tcx().sess, field.ident.span, E0062,
+ if let Some(_) = variant.find_field_named(field.name.node) {
+ span_err!(fcx.tcx().sess, field.name.span, E0062,
"field `{}` specified more than once",
- field.ident.node);
+ field.name.node);
} else {
report_unknown_field(fcx, adt_ty, variant, field, ast_fields);
}
// Find the relevant variant
let def = lookup_full_def(tcx, path.span, expr.id);
- let (adt, variant) = match fcx.def_struct_variant(def) {
+ let (adt, variant) = match fcx.def_struct_variant(def, path.span) {
Some((adt, variant)) => (adt, variant),
None => {
span_err!(fcx.tcx().sess, path.span, E0071,
let tcx = fcx.ccx.tcx;
let id = expr.id;
match expr.node {
- hir::ExprBox(ref opt_place, ref subexpr) => {
- opt_place.as_ref().map(|place|check_expr(fcx, &**place));
- check_expr(fcx, &**subexpr);
-
- let mut checked = false;
- opt_place.as_ref().map(|place| match place.node {
- hir::ExprPath(None, ref path) => {
- // FIXME(pcwalton): For now we hardcode the only permissible
- // place: the exchange heap.
- let definition = lookup_full_def(tcx, path.span, place.id);
- let def_id = definition.def_id();
- let referent_ty = fcx.expr_ty(&**subexpr);
- if tcx.lang_items.exchange_heap() == Some(def_id) {
- fcx.write_ty(id, tcx.mk_box(referent_ty));
- checked = true
- }
- }
- _ => {}
- });
-
- if !checked {
- span_err!(tcx.sess, expr.span, E0066,
- "only the exchange heap is currently supported");
- fcx.write_ty(id, tcx.types.err);
- }
+ hir::ExprBox(ref subexpr) => {
+ let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| {
+ match ty.sty {
+ ty::TyBox(ty) => Expectation::rvalue_hint(tcx, ty),
+ _ => NoExpectation
+ }
+ });
+ check_expr_with_expectation(fcx, subexpr, expected_inner);
+ let referent_ty = fcx.expr_ty(&**subexpr);
+ fcx.write_ty(id, tcx.mk_box(referent_ty));
}
hir::ExprLit(ref lit) => {
op::check_binop_assign(fcx, expr, op, lhs, rhs);
}
hir::ExprUnary(unop, ref oprnd) => {
- let expected_inner = expected.to_option(fcx).map_or(NoExpectation, |ty| {
- match unop {
- hir::UnUniq => match ty.sty {
- ty::TyBox(ty) => {
- Expectation::rvalue_hint(tcx, ty)
- }
- _ => {
- NoExpectation
- }
- },
- hir::UnNot | hir::UnNeg => {
- expected
- }
- hir::UnDeref => {
- NoExpectation
- }
+ let expected_inner = match unop {
+ hir::UnNot | hir::UnNeg => {
+ expected
}
- });
+ hir::UnDeref => {
+ NoExpectation
+ }
+ };
let lvalue_pref = match unop {
hir::UnDeref => lvalue_pref,
_ => NoPreference
if !oprnd_t.references_error() {
match unop {
- hir::UnUniq => {
- oprnd_t = tcx.mk_box(oprnd_t);
- }
hir::UnDeref => {
oprnd_t = structurally_resolved_type(fcx, expr.span, oprnd_t);
oprnd_t = match oprnd_t.builtin_deref(true, NoPreference) {
} else if let Some(hir::QSelf { position: 0, .. }) = *maybe_qself {
// Create some fake resolution that can't possibly be a type.
def::PathResolution {
- base_def: def::DefMod(DefId::local(ast::CRATE_NODE_ID)),
+ base_def: def::DefMod(tcx.map.local_def_id(ast::CRATE_NODE_ID)),
last_private: LastMod(AllPublic),
depth: path.segments.len()
}
}
fcx.write_ty(id, fcx.infcx().next_diverging_ty_var());
}
- hir::ExprParen(ref a) => {
- check_expr_with_expectation_and_lvalue_pref(fcx,
- &**a,
- expected,
- lvalue_pref);
- fcx.write_ty(id, fcx.expr_ty(&**a));
- }
hir::ExprAssign(ref lhs, ref rhs) => {
check_expr_with_lvalue_pref(fcx, &**lhs, PreferMutLvalue);
let ret_ty = fcx.expr_ty(expr);
fcx.register_wf_obligation(ret_ty, expr.span, traits::MiscObligation);
}
- hir::ExprMethodCall(ident, ref tps, ref args) => {
- check_method_call(fcx, expr, ident, &args[..], &tps[..], expected, lvalue_pref);
+ hir::ExprMethodCall(name, ref tps, ref args) => {
+ check_method_call(fcx, expr, name, &args[..], &tps[..], expected, lvalue_pref);
let arg_tys = args.iter().map(|a| fcx.expr_ty(&**a));
let args_err = arg_tys.fold(false, |rest_err, a| rest_err || a.references_error());
if args_err {
let inh = static_inherited_fields(ccx, &tables);
let rty = ccx.tcx.node_id_to_type(id);
let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(rty), e.id);
- let declty = fcx.ccx.tcx.lookup_item_type(DefId::local(id)).ty;
+ let declty = fcx.ccx.tcx.lookup_item_type(ccx.tcx.map.local_def_id(id)).ty;
check_const_with_ty(&fcx, sp, e, declty);
}
// Gather locals in statics (because of block expressions).
// This is technically unnecessary because locals in static items are forbidden,
// but prevents type checking from blowing up before const checking can properly
- // emit a error.
+ // emit an error.
GatherLocalsVisitor { fcx: fcx }.visit_expr(e);
check_expr_with_hint(fcx, e, declty);
fn disr_in_range(ccx: &CrateCtxt,
ty: attr::IntType,
disr: ty::Disr) -> bool {
- fn uint_in_range(ccx: &CrateCtxt, ty: hir::UintTy, disr: ty::Disr) -> bool {
+ fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
match ty {
- hir::TyU8 => disr as u8 as Disr == disr,
- hir::TyU16 => disr as u16 as Disr == disr,
- hir::TyU32 => disr as u32 as Disr == disr,
- hir::TyU64 => disr as u64 as Disr == disr,
- hir::TyUs => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
+ ast::TyU8 => disr as u8 as Disr == disr,
+ ast::TyU16 => disr as u16 as Disr == disr,
+ ast::TyU32 => disr as u32 as Disr == disr,
+ ast::TyU64 => disr as u64 as Disr == disr,
+ ast::TyUs => uint_in_range(ccx, ccx.tcx.sess.target.uint_type, disr)
}
}
- fn int_in_range(ccx: &CrateCtxt, ty: hir::IntTy, disr: ty::Disr) -> bool {
+ fn int_in_range(ccx: &CrateCtxt, ty: ast::IntTy, disr: ty::Disr) -> bool {
match ty {
- hir::TyI8 => disr as i8 as Disr == disr,
- hir::TyI16 => disr as i16 as Disr == disr,
- hir::TyI32 => disr as i32 as Disr == disr,
- hir::TyI64 => disr as i64 as Disr == disr,
- hir::TyIs => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
+ ast::TyI8 => disr as i8 as Disr == disr,
+ ast::TyI16 => disr as i16 as Disr == disr,
+ ast::TyI32 => disr as i32 as Disr == disr,
+ ast::TyI64 => disr as i64 as Disr == disr,
+ ast::TyIs => int_in_range(ccx, ccx.tcx.sess.target.int_type, disr)
}
}
match ty {
}
}
- let def_id = DefId::local(id);
+ let def_id = ccx.tcx.map.local_def_id(id);
let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
for (v, variant) in vs.iter().zip(variants.iter()) {
Some(i) => {
span_err!(ccx.tcx.sess, v.span, E0081,
"discriminant value `{}` already exists", disr_vals[i]);
- span_note!(ccx.tcx.sess, ccx.tcx.map.span(variants[i].did.node),
+ let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
+ span_note!(ccx.tcx.sess, ccx.tcx.map.span(variant_i_node_id),
"conflicting discriminant here")
}
None => {}
}
}
- let hint = *ccx.tcx.lookup_repr_hints(DefId { krate: LOCAL_CRATE, node: id })
- .get(0).unwrap_or(&attr::ReprAny);
+ let def_id = ccx.tcx.map.local_def_id(id);
+ let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
if hint != attr::ReprAny && vs.len() <= 1 {
if vs.len() == 1 {
defn: def::Def)
-> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
match defn {
- def::DefLocal(nid) | def::DefUpvar(nid, _, _) => {
+ def::DefLocal(_, nid) | def::DefUpvar(_, nid, _, _) => {
let typ = fcx.local_ty(sp, nid);
(ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
ty::GenericPredicates::empty())
def::DefMod(..) |
def::DefForeignMod(..) |
def::DefUse(..) |
- def::DefRegion(..) |
def::DefLabel(..) |
def::DefSelfTy(..) => {
fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
// parameters permitted at present, but perhaps we will allow
// them in the future.)
//
- // 1b. Reference to a enum variant or tuple-like struct:
+ // 1b. Reference to an enum variant or tuple-like struct:
//
// struct foo<T>(...)
// enum E<T> { foo(...) }
def::DefForeignMod(..) |
def::DefLocal(..) |
def::DefUse(..) |
- def::DefRegion(..) |
def::DefLabel(..) |
def::DefUpvar(..) => {
segment_spaces = vec![None; segments.len()];
if !*b {
span_err!(ccx.tcx.sess, span, E0091,
"type parameter `{}` is unused",
- tps[i].ident);
+ tps[i].name);
}
}
}
demand,
method,
FnCtxt,
- structurally_resolved_type,
};
use middle::def_id::DefId;
-use middle::traits;
use middle::ty::{Ty, HasTypeFlags, PreferMutLvalue};
use syntax::ast;
use syntax::parse::token;
lhs_expr: &'tcx hir::Expr,
rhs_expr: &'tcx hir::Expr)
{
- let tcx = fcx.ccx.tcx;
-
check_expr_with_lvalue_pref(fcx, lhs_expr, PreferMutLvalue);
- check_expr(fcx, rhs_expr);
- let lhs_ty = structurally_resolved_type(fcx, lhs_expr.span, fcx.expr_ty(lhs_expr));
- let rhs_ty = structurally_resolved_type(fcx, rhs_expr.span, fcx.expr_ty(rhs_expr));
+ let lhs_ty = fcx.resolve_type_vars_if_possible(fcx.expr_ty(lhs_expr));
+ let (rhs_ty, return_ty) =
+ check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::Yes);
+ let rhs_ty = fcx.resolve_type_vars_if_possible(rhs_ty);
- if is_builtin_binop(lhs_ty, rhs_ty, op) {
+ if !lhs_ty.is_ty_var() && !rhs_ty.is_ty_var() && is_builtin_binop(lhs_ty, rhs_ty, op) {
enforce_builtin_binop_types(fcx, lhs_expr, lhs_ty, rhs_expr, rhs_ty, op);
fcx.write_nil(expr.id);
} else {
- // error types are considered "builtin"
- assert!(!lhs_ty.references_error() || !rhs_ty.references_error());
- span_err!(tcx.sess, lhs_expr.span, E0368,
- "binary assignment operation `{}=` cannot be applied to types `{}` and `{}`",
- hir_util::binop_to_string(op.node),
- lhs_ty,
- rhs_ty);
- fcx.write_error(expr.id);
+ fcx.write_ty(expr.id, return_ty);
}
let tcx = fcx.tcx();
if !tcx.expr_is_lval(lhs_expr) {
span_err!(tcx.sess, lhs_expr.span, E0067, "invalid left-hand side expression");
}
-
- fcx.require_expr_have_sized_type(lhs_expr, traits::AssignmentLhsSized);
}
/// Check a potentially overloaded binary operator.
// overloaded. This is the way to be most flexible w/r/t
// types that get inferred.
let (rhs_ty, return_ty) =
- check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op);
+ check_overloaded_binop(fcx, expr, lhs_expr, lhs_ty, rhs_expr, op, IsAssign::No);
// Supply type inference hints if relevant. Probably these
// hints should be enforced during select as part of the
lhs_expr: &'tcx hir::Expr,
lhs_ty: Ty<'tcx>,
rhs_expr: &'tcx hir::Expr,
- op: hir::BinOp)
+ op: hir::BinOp,
+ is_assign: IsAssign)
-> (Ty<'tcx>, Ty<'tcx>)
{
- debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?})",
+ debug!("check_overloaded_binop(expr.id={}, lhs_ty={:?}, is_assign={:?})",
expr.id,
- lhs_ty);
+ lhs_ty,
+ is_assign);
- let (name, trait_def_id) = name_and_trait_def_id(fcx, op);
+ let (name, trait_def_id) = name_and_trait_def_id(fcx, op, is_assign);
// NB: As we have not yet type-checked the RHS, we don't have the
// type at hand. Make a variable to represent it. The whole reason
Err(()) => {
// error types are considered "builtin"
if !lhs_ty.references_error() {
- span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
- "binary operation `{}` cannot be applied to type `{}`",
- hir_util::binop_to_string(op.node),
- lhs_ty);
+ if let IsAssign::Yes = is_assign {
+ span_err!(fcx.tcx().sess, lhs_expr.span, E0368,
+ "binary assignment operation `{}=` cannot be applied to type `{}`",
+ hir_util::binop_to_string(op.node),
+ lhs_ty);
+ } else {
+ span_err!(fcx.tcx().sess, lhs_expr.span, E0369,
+ "binary operation `{}` cannot be applied to type `{}`",
+ hir_util::binop_to_string(op.node),
+ lhs_ty);
+ let missing_trait = match op.node {
+ hir::BiAdd => Some("std::ops::Add"),
+ hir::BiSub => Some("std::ops::Sub"),
+ hir::BiMul => Some("std::ops::Mul"),
+ hir::BiDiv => Some("std::ops::Div"),
+ hir::BiRem => Some("std::ops::Rem"),
+ hir::BiBitAnd => Some("std::ops::BitAnd"),
+ hir::BiBitOr => Some("std::ops::BitOr"),
+ hir::BiShl => Some("std::ops::Shl"),
+ hir::BiShr => Some("std::ops::Shr"),
+ hir::BiEq | hir::BiNe => Some("std::cmp::PartialEq"),
+ hir::BiLt | hir::BiLe | hir::BiGt | hir::BiGe =>
+ Some("std::cmp::PartialOrd"),
+ _ => None
+ };
+
+ if let Some(missing_trait) = missing_trait {
+ span_note!(fcx.tcx().sess, lhs_expr.span,
+ "an implementation of `{}` might be missing for `{}`",
+ missing_trait, lhs_ty);
+ }
+ }
}
fcx.tcx().types.err
}
}
}
-fn name_and_trait_def_id(fcx: &FnCtxt, op: hir::BinOp) -> (&'static str, Option<DefId>) {
+fn name_and_trait_def_id(fcx: &FnCtxt,
+ op: hir::BinOp,
+ is_assign: IsAssign)
+ -> (&'static str, Option<DefId>) {
let lang = &fcx.tcx().lang_items;
- match op.node {
- hir::BiAdd => ("add", lang.add_trait()),
- hir::BiSub => ("sub", lang.sub_trait()),
- hir::BiMul => ("mul", lang.mul_trait()),
- hir::BiDiv => ("div", lang.div_trait()),
- hir::BiRem => ("rem", lang.rem_trait()),
- hir::BiBitXor => ("bitxor", lang.bitxor_trait()),
- hir::BiBitAnd => ("bitand", lang.bitand_trait()),
- hir::BiBitOr => ("bitor", lang.bitor_trait()),
- hir::BiShl => ("shl", lang.shl_trait()),
- hir::BiShr => ("shr", lang.shr_trait()),
- hir::BiLt => ("lt", lang.ord_trait()),
- hir::BiLe => ("le", lang.ord_trait()),
- hir::BiGe => ("ge", lang.ord_trait()),
- hir::BiGt => ("gt", lang.ord_trait()),
- hir::BiEq => ("eq", lang.eq_trait()),
- hir::BiNe => ("ne", lang.eq_trait()),
- hir::BiAnd | hir::BiOr => {
- fcx.tcx().sess.span_bug(op.span, "&& and || are not overloadable")
+
+ if let IsAssign::Yes = is_assign {
+ match op.node {
+ hir::BiAdd => ("add_assign", lang.add_assign_trait()),
+ hir::BiSub => ("sub_assign", lang.sub_assign_trait()),
+ hir::BiMul => ("mul_assign", lang.mul_assign_trait()),
+ hir::BiDiv => ("div_assign", lang.div_assign_trait()),
+ hir::BiRem => ("rem_assign", lang.rem_assign_trait()),
+ hir::BiBitXor => ("bitxor_assign", lang.bitxor_assign_trait()),
+ hir::BiBitAnd => ("bitand_assign", lang.bitand_assign_trait()),
+ hir::BiBitOr => ("bitor_assign", lang.bitor_assign_trait()),
+ hir::BiShl => ("shl_assign", lang.shl_assign_trait()),
+ hir::BiShr => ("shr_assign", lang.shr_assign_trait()),
+ hir::BiLt | hir::BiLe | hir::BiGe | hir::BiGt | hir::BiEq | hir::BiNe | hir::BiAnd |
+ hir::BiOr => {
+ fcx.tcx().sess.span_bug(op.span, &format!("impossible assignment operation: {}=",
+ hir_util::binop_to_string(op.node)))
+ }
+ }
+ } else {
+ match op.node {
+ hir::BiAdd => ("add", lang.add_trait()),
+ hir::BiSub => ("sub", lang.sub_trait()),
+ hir::BiMul => ("mul", lang.mul_trait()),
+ hir::BiDiv => ("div", lang.div_trait()),
+ hir::BiRem => ("rem", lang.rem_trait()),
+ hir::BiBitXor => ("bitxor", lang.bitxor_trait()),
+ hir::BiBitAnd => ("bitand", lang.bitand_trait()),
+ hir::BiBitOr => ("bitor", lang.bitor_trait()),
+ hir::BiShl => ("shl", lang.shl_trait()),
+ hir::BiShr => ("shr", lang.shr_trait()),
+ hir::BiLt => ("lt", lang.ord_trait()),
+ hir::BiLe => ("le", lang.ord_trait()),
+ hir::BiGe => ("ge", lang.ord_trait()),
+ hir::BiGt => ("gt", lang.ord_trait()),
+ hir::BiEq => ("eq", lang.eq_trait()),
+ hir::BiNe => ("ne", lang.eq_trait()),
+ hir::BiAnd | hir::BiOr => {
+ fcx.tcx().sess.span_bug(op.span, "&& and || are not overloadable")
+ }
}
}
}
}
}
+/// Whether the binary operation is an assignment (`a += b`), or not (`a + b`)
+#[derive(Clone, Copy, Debug)]
+enum IsAssign {
+ No,
+ Yes,
+}
+
/// Returns true if this is a built-in arithmetic operation (e.g. u32
/// + u32, i16x4 == i16x4) and false if these types would have to be
/// overloaded to be legal. There are two reasons that we distinguish
//! borrowed pointer? I mean any data that is reached by first
//! dereferencing a borrowed pointer and then either traversing
//! interior offsets or boxes. We say that the guarantor
-//! of such data it the region of the borrowed pointer that was
+//! of such data is the region of the borrowed pointer that was
//! traversed. This is essentially the same as the ownership
//! relation, except that a borrowed pointer never owns its
//! contents.
};
substs_wf_in_scope(rcx, origin, &callee.substs, expr.span, expr_region);
+ type_must_outlive(rcx, infer::ExprTypeIsNotInScope(callee.ty, expr.span),
+ callee.ty, expr_region);
}
// Check any autoderefs or autorefs that appear.
}
}
+ debug!("regionck::visit_expr(e={:?}, repeating_scope={}) - visiting subexprs",
+ expr, rcx.repeating_scope);
match expr.node {
hir::ExprPath(..) => {
rcx.fcx.opt_node_ty_substs(expr.id, |item_substs| {
hir::ExprAssignOp(_, ref lhs, ref rhs) => {
if has_method_map {
constrain_call(rcx, expr, Some(&**lhs),
- Some(&**rhs).into_iter(), true);
+ Some(&**rhs).into_iter(), false);
}
visit::walk_expr(rcx, expr);
let arg_ty = rcx.fcx.node_ty(arg.id);
let re_scope = ty::ReScope(body_scope);
let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
- debug!("arg_ty={:?} arg_cmt={:?}",
+ debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
arg_ty,
- arg_cmt);
+ arg_cmt,
+ arg);
link_pattern(rcx, mc, arg_cmt, &*arg.pat);
}
}
{
let ty = rcx.resolve_type(ty);
- debug!("type_must_outlive(ty={:?}, region={:?})",
+ debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})",
ty,
- region);
+ region,
+ origin);
assert!(!ty.has_escaping_regions());
use super::FnCtxt;
use check::demand;
-use middle::def_id::DefId;
use middle::expr_use_visitor as euv;
use middle::mem_categorization as mc;
use middle::ty::{self, Ty};
capture_clause: hir::CaptureClause,
_body: &hir::Block)
{
- let closure_def_id = DefId::local(expr.id);
+ let closure_def_id = self.tcx().map.local_def_id(expr.id);
if !self.fcx.inh.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
self.closures_with_inferred_kinds.insert(expr.id);
self.fcx.inh.tables.borrow_mut().closure_kinds
self.tcx().with_freevars(expr.id, |freevars| {
for freevar in freevars {
- let var_node_id = freevar.def.local_node_id();
+ let var_node_id = freevar.def.var_id();
let upvar_id = ty::UpvarId { var_id: var_node_id,
closure_expr_id: expr.id };
debug!("seed upvar_id {:?}", upvar_id);
// Now we must process and remove any deferred resolutions,
// since we have a concrete closure kind.
- let closure_def_id = DefId::local(id);
+ let closure_def_id = self.fcx.tcx().map.local_def_id(id);
if self.closures_with_inferred_kinds.contains(&id) {
let mut deferred_call_resolutions =
self.fcx.remove_deferred_call_resolutions(closure_def_id);
tcx.with_freevars(closure_id, |freevars| {
freevars.iter()
.map(|freevar| {
- let freevar_def_id = freevar.def.def_id();
- let freevar_ty = self.fcx.node_ty(freevar_def_id.node);
+ let freevar_node_id = freevar.def.var_id();
+ let freevar_ty = self.fcx.node_ty(freevar_node_id);
let upvar_id = ty::UpvarId {
- var_id: freevar_def_id.node,
+ var_id: freevar_node_id,
closure_expr_id: closure_id
};
let capture = self.fcx.infcx().upvar_capture(upvar_id).unwrap();
- debug!("freevar_def_id={:?} freevar_ty={:?} capture={:?}",
- freevar_def_id, freevar_ty, capture);
+ debug!("freevar_node_id={:?} freevar_ty={:?} capture={:?}",
+ freevar_node_id, freevar_ty, capture);
match capture {
ty::UpvarCapture::ByValue => freevar_ty,
return;
}
- let closure_def_id = DefId::local(closure_id);
+ let closure_def_id = self.fcx.tcx().map.local_def_id(closure_id);
let closure_kinds = &mut self.fcx.inh.tables.borrow_mut().closure_kinds;
let existing_kind = *closure_kinds.get(&closure_def_id).unwrap();
use check::{FnCtxt, Inherited, blank_fn_ctxt, regionck, wfcheck};
use constrained_type_params::{identify_constrained_type_params, Parameter};
use CrateCtxt;
-use middle::def_id::DefId;
use middle::region;
use middle::subst::{self, TypeSpace, FnSpace, ParamSpace, SelfSpace};
use middle::traits;
/// the types first.
fn check_item_well_formed(&mut self, item: &hir::Item) {
let ccx = self.ccx;
- debug!("check_item_well_formed(it.id={}, it.ident={})",
+ debug!("check_item_well_formed(it.id={}, it.name={})",
item.id,
- ccx.tcx.item_path_str(DefId::local(item.id)));
+ ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(item.id)));
match item.node {
/// Right now we check that every default trait implementation
self.check_impl(item);
}
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => {
- let trait_ref = ccx.tcx.impl_trait_ref(DefId::local(item.id)).unwrap();
+ let item_def_id = ccx.tcx.map.local_def_id(item.id);
+ let trait_ref = ccx.tcx.impl_trait_ref(item_def_id).unwrap();
ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id);
match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
Some(ty::BoundSend) | Some(ty::BoundSync) => {}
}
hir::ItemStruct(ref struct_def, ref ast_generics) => {
self.check_type_defn(item, |fcx| {
- vec![struct_variant(fcx, &**struct_def)]
+ vec![struct_variant(fcx, struct_def)]
});
self.check_variances_for_type_defn(item, ast_generics);
}
hir::ItemTrait(_, _, _, ref items) => {
let trait_predicates =
- ccx.tcx.lookup_predicates(DefId::local(item.id));
+ ccx.tcx.lookup_predicates(ccx.tcx.map.local_def_id(item.id));
reject_non_type_param_bounds(ccx.tcx, item.span, &trait_predicates);
- if ccx.tcx.trait_has_default_impl(DefId::local(item.id)) {
+ if ccx.tcx.trait_has_default_impl(ccx.tcx.map.local_def_id(item.id)) {
if !items.is_empty() {
wfcheck::error_380(ccx, item.span);
}
F: for<'fcx> FnMut(&mut CheckTypeWellFormedVisitor<'ccx, 'tcx>, &FnCtxt<'fcx, 'tcx>),
{
let ccx = self.ccx;
- let item_def_id = DefId::local(item.id);
+ let item_def_id = ccx.tcx.map.local_def_id(item.id);
let type_scheme = ccx.tcx.lookup_item_type(item_def_id);
let type_predicates = ccx.tcx.lookup_predicates(item_def_id);
reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates);
Some(&mut this.cache));
debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope);
- let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id));
+ let item_def_id = fcx.tcx().map.local_def_id(item.id);
+ let type_scheme = fcx.tcx().lookup_item_type(item_def_id);
let item_ty = fcx.instantiate_type_scheme(item.span,
&fcx.inh
.infcx
// Similarly, obtain an "inside" reference to the trait
// that the impl implements.
- let trait_ref = match fcx.tcx().impl_trait_ref(DefId::local(item.id)) {
+ let trait_ref = match fcx.tcx().impl_trait_ref(fcx.tcx().map.local_def_id(item.id)) {
None => { return; }
Some(t) => { t }
};
item: &hir::Item,
ast_generics: &hir::Generics)
{
- let item_def_id = DefId::local(item.id);
+ let item_def_id = self.tcx().map.local_def_id(item.id);
let ty_predicates = self.tcx().lookup_predicates(item_def_id);
let variances = self.tcx().item_variances(item_def_id);
-> ty::ParamTy
{
let name = match space {
- TypeSpace => ast_generics.ty_params[index].ident.name,
+ TypeSpace => ast_generics.ty_params[index].name,
SelfSpace => special_idents::type_self.name,
FnSpace => self.tcx().sess.bug("Fn space occupied?"),
};
match fk {
FnKind::Closure | FnKind::ItemFn(..) => {}
FnKind::Method(..) => {
- match self.tcx().impl_or_trait_item(DefId::local(id)) {
+ match self.tcx().impl_or_trait_item(self.tcx().map.local_def_id(id)) {
ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
reject_shadowing_type_parameters(self.tcx(), span, &ty_method.generics)
}
fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
if let hir::MethodTraitItem(_, None) = trait_item.node {
- match self.tcx().impl_or_trait_item(DefId::local(trait_item.id)) {
+ match self.tcx().impl_or_trait_item(self.tcx().map.local_def_id(trait_item.id)) {
ty::ImplOrTraitItem::MethodTraitItem(ty_method) => {
reject_non_type_param_bounds(
self.tcx(),
}
fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- struct_def: &hir::StructDef)
+ struct_def: &hir::VariantData)
-> AdtVariant<'tcx> {
let fields =
- struct_def.fields
- .iter()
+ struct_def.fields().iter()
.map(|field| {
let field_ty = fcx.tcx().node_id_to_type(field.node.id);
let field_ty = fcx.instantiate_type_scheme(field.span,
enum_def: &hir::EnumDef)
-> Vec<AdtVariant<'tcx>> {
enum_def.variants.iter()
- .map(|variant| {
- match variant.node.kind {
- hir::TupleVariantKind(ref args) if !args.is_empty() => {
- let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id);
-
- // the regions in the argument types come from the
- // enum def'n, and hence will all be early bound
- let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap();
- AdtVariant {
- fields: args.iter().enumerate().map(|(index, arg)| {
- let arg_ty = arg_tys[index];
- let arg_ty =
- fcx.instantiate_type_scheme(variant.span,
- &fcx.inh
- .infcx
- .parameter_environment
- .free_substs,
- &arg_ty);
- AdtField {
- ty: arg_ty,
- span: arg.ty.span
- }
- }).collect()
- }
- }
- hir::TupleVariantKind(_) => {
- AdtVariant {
- fields: Vec::new()
- }
- }
- hir::StructVariantKind(ref struct_def) => {
- struct_variant(fcx, &**struct_def)
- }
- }
- })
+ .map(|variant| struct_variant(fcx, &variant.node.data))
.collect()
}
/// the types first.
fn check_item_well_formed(&mut self, item: &hir::Item) {
let ccx = self.ccx;
- debug!("check_item_well_formed(it.id={}, it.ident={})",
+ debug!("check_item_well_formed(it.id={}, it.name={})",
item.id,
- ccx.tcx.item_path_str(DefId::local(item.id)));
+ ccx.tcx.item_path_str(ccx.tcx.map.local_def_id(item.id)));
match item.node {
/// Right now we check that every default trait implementation
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), _, _) => {
// FIXME(#27579) what amount of WF checking do we need for neg impls?
- let trait_ref = ccx.tcx.impl_trait_ref(DefId::local(item.id)).unwrap();
+ let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.map.local_def_id(item.id)).unwrap();
ccx.tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id);
match ccx.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
Some(ty::BoundSend) | Some(ty::BoundSync) => {}
}
hir::ItemStruct(ref struct_def, ref ast_generics) => {
self.check_type_defn(item, |fcx| {
- vec![struct_variant(fcx, &**struct_def)]
+ vec![struct_variant(fcx, struct_def)]
});
self.check_variances_for_type_defn(item, ast_generics);
let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
let free_id = fcx.inh.infcx.parameter_environment.free_id;
- let item = fcx.tcx().impl_or_trait_item(DefId::local(item_id));
+ let item = fcx.tcx().impl_or_trait_item(fcx.tcx().map.local_def_id(item_id));
let mut implied_bounds = match item.container() {
ty::TraitContainer(_) => vec![],
}
let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
- let predicates = fcx.tcx().lookup_predicates(DefId::local(item.id));
+ let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
this.check_where_clauses(fcx, item.span, &predicates);
item: &hir::Item,
items: &[P<hir::TraitItem>])
{
- let trait_def_id = DefId::local(item.id);
+ let trait_def_id = self.tcx().map.local_def_id(item.id);
if self.ccx.tcx.trait_has_default_impl(trait_def_id) {
if !items.is_empty() {
{
self.with_item_fcx(item, |fcx, this| {
let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
- let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id));
+ let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &type_scheme.ty);
let bare_fn_ty = match item_ty.sty {
ty::TyBareFn(_, ref bare_fn_ty) => bare_fn_ty,
}
};
- let predicates = fcx.tcx().lookup_predicates(DefId::local(item.id));
+ let predicates = fcx.tcx().lookup_predicates(fcx.tcx().map.local_def_id(item.id));
let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
let mut implied_bounds = vec![];
debug!("check_item_type: {:?}", item);
self.with_item_fcx(item, |fcx, this| {
- let type_scheme = fcx.tcx().lookup_item_type(DefId::local(item.id));
+ let type_scheme = fcx.tcx().lookup_item_type(fcx.tcx().map.local_def_id(item.id));
let item_ty = fcx.instantiate_type_scheme(item.span,
&fcx.inh
.infcx
self.with_item_fcx(item, |fcx, this| {
let free_substs = &fcx.inh.infcx.parameter_environment.free_substs;
- let item_def_id = DefId::local(item.id);
+ let item_def_id = fcx.tcx().map.local_def_id(item.id);
match *ast_trait_ref {
Some(ref ast_trait_ref) => {
let predicates = fcx.instantiate_bounds(item.span, free_substs, &predicates);
this.check_where_clauses(fcx, item.span, &predicates);
- impl_implied_bounds(fcx, DefId::local(item.id), item.span)
+ impl_implied_bounds(fcx, fcx.tcx().map.local_def_id(item.id), item.span)
});
}
item: &hir::Item,
ast_generics: &hir::Generics)
{
- let item_def_id = DefId::local(item.id);
+ let item_def_id = self.tcx().map.local_def_id(item.id);
let ty_predicates = self.tcx().lookup_predicates(item_def_id);
let variances = self.tcx().item_variances(item_def_id);
-> ty::ParamTy
{
let name = match space {
- TypeSpace => ast_generics.ty_params[index].ident.name,
+ TypeSpace => ast_generics.ty_params[index].name,
SelfSpace => special_idents::type_self.name,
FnSpace => self.tcx().sess.bug("Fn space occupied?"),
};
}
fn struct_variant<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
- struct_def: &hir::StructDef)
+ struct_def: &hir::VariantData)
-> AdtVariant<'tcx> {
let fields =
- struct_def.fields
- .iter()
+ struct_def.fields().iter()
.map(|field| {
let field_ty = fcx.tcx().node_id_to_type(field.node.id);
let field_ty = fcx.instantiate_type_scheme(field.span,
enum_def: &hir::EnumDef)
-> Vec<AdtVariant<'tcx>> {
enum_def.variants.iter()
- .map(|variant| {
- match variant.node.kind {
- hir::TupleVariantKind(ref args) if !args.is_empty() => {
- let ctor_ty = fcx.tcx().node_id_to_type(variant.node.id);
-
- // the regions in the argument types come from the
- // enum def'n, and hence will all be early bound
- let arg_tys = fcx.tcx().no_late_bound_regions(&ctor_ty.fn_args()).unwrap();
- AdtVariant {
- fields: args.iter().enumerate().map(|(index, arg)| {
- let arg_ty = arg_tys[index];
- let arg_ty =
- fcx.instantiate_type_scheme(variant.span,
- &fcx.inh
- .infcx
- .parameter_environment
- .free_substs,
- &arg_ty);
- AdtField {
- ty: arg_ty,
- span: arg.ty.span
- }
- }).collect()
- }
- }
- hir::TupleVariantKind(_) => {
- AdtVariant {
- fields: Vec::new()
- }
- }
- hir::StructVariantKind(ref struct_def) => {
- struct_variant(fcx, &**struct_def)
- }
- }
- })
+ .map(|variant| struct_variant(fcx, &variant.node.data))
.collect()
}
use check::FnCtxt;
use middle::def_id::DefId;
use middle::pat_util;
-use middle::ty::{self, Ty, MethodCall, MethodCallee};
+use middle::ty::{self, Ty, MethodCall, MethodCallee, HasTypeFlags};
use middle::ty::adjustment;
use middle::ty::fold::{TypeFolder,TypeFoldable};
use middle::infer;
// we observe that something like `a+b` is (known to be)
// operating on scalars, we clear the overload.
fn fix_scalar_binary_expr(&mut self, e: &hir::Expr) {
- if let hir::ExprBinary(ref op, ref lhs, ref rhs) = e.node {
- let lhs_ty = self.fcx.node_ty(lhs.id);
- let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
-
- let rhs_ty = self.fcx.node_ty(rhs.id);
- let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
-
- if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
- self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
-
- // weird but true: the by-ref binops put an
- // adjustment on the lhs but not the rhs; the
- // adjustment for rhs is kind of baked into the
- // system.
- if !hir_util::is_by_value_binop(op.node) {
- self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
+ match e.node {
+ hir::ExprBinary(ref op, ref lhs, ref rhs) |
+ hir::ExprAssignOp(ref op, ref lhs, ref rhs) => {
+ let lhs_ty = self.fcx.node_ty(lhs.id);
+ let lhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&lhs_ty);
+
+ let rhs_ty = self.fcx.node_ty(rhs.id);
+ let rhs_ty = self.fcx.infcx().resolve_type_vars_if_possible(&rhs_ty);
+
+ if lhs_ty.is_scalar() && rhs_ty.is_scalar() {
+ self.fcx.inh.tables.borrow_mut().method_map.remove(&MethodCall::expr(e.id));
+
+ // weird but true: the by-ref binops put an
+ // adjustment on the lhs but not the rhs; the
+ // adjustment for rhs is kind of baked into the
+ // system.
+ match e.node {
+ hir::ExprBinary(..) => {
+ if !hir_util::is_by_value_binop(op.node) {
+ self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
+ }
+ },
+ hir::ExprAssignOp(..) => {
+ self.fcx.inh.tables.borrow_mut().adjustments.remove(&lhs.id);
+ },
+ _ => {},
+ }
+ } else {
+ let tcx = self.tcx();
+
+ if let hir::ExprAssignOp(..) = e.node {
+ if
+ !tcx.sess.features.borrow().augmented_assignments &&
+ !self.fcx.expr_ty(e).references_error()
+ {
+ tcx.sess.span_err(
+ e.span,
+ "overloaded augmented assignments are not stable");
+ fileline_help!(
+ tcx.sess, e.span,
+ "add #![feature(augmented_assignments)] to the crate root \
+ to enable");
+ }
+ }
}
}
+ _ => {},
}
}
}
self.visit_ty(&**ty);
write_ty_to_tcx(self.tcx(), count_expr.id, self.tcx().types.usize);
}
+ hir::TyBareFn(ref function_declaration) => {
+ visit::walk_fn_decl_nopat(self, &function_declaration.decl);
+ walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
+ }
_ => visit::walk_ty(self, t)
}
}
tcx.expr_span(upvar_id.closure_expr_id)
}
ResolvingClosure(did) => {
- if did.is_local() {
- tcx.expr_span(did.node)
+ if let Some(node_id) = tcx.map.as_local_node_id(did) {
+ tcx.expr_span(node_id)
} else {
DUMMY_SP
}
// mappings. That mapping code resides here.
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::lang_items::UnsizeTraitLangItem;
use middle::subst::{self, Subst};
use middle::traits;
use middle::ty;
use middle::ty::RegionEscape;
-use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
+use middle::ty::{ImplOrTraitItemId, ConstTraitItemId};
use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
use middle::ty::{Ty, TyBool, TyChar, TyEnum, TyError};
-use middle::ty::{TyParam, TypeScheme, TyRawPtr};
+use middle::ty::{TyParam, TyRawPtr};
use middle::ty::{TyRef, TyStruct, TyTrait, TyTuple};
use middle::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
use middle::ty::{TyUint, TyClosure, TyBox, TyBareFn};
fn check_implementation(&self, item: &Item) {
let tcx = self.crate_context.tcx;
- let impl_did = DefId::local(item.id);
+ let impl_did = tcx.map.local_def_id(item.id);
let self_type = tcx.lookup_item_type(impl_did);
// If there are no traits, then this implementation must have a
if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) {
debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
trait_ref,
- item.ident);
+ item.name);
enforce_trait_manually_implementable(self.crate_context.tcx,
item.span,
tcx.impl_items.borrow_mut().insert(impl_did, impl_items);
}
- // Creates default method IDs and performs type substitutions for an impl
- // and trait pair. Then, for each provided method in the trait, inserts a
- // `ProvidedMethodInfo` instance into the `provided_method_sources` map.
- fn instantiate_default_methods(
- &self,
- impl_id: DefId,
- trait_ref: &ty::TraitRef<'tcx>,
- all_impl_items: &mut Vec<ImplOrTraitItemId>) {
- let tcx = self.crate_context.tcx;
- debug!("instantiate_default_methods(impl_id={:?}, trait_ref={:?})",
- impl_id, trait_ref);
-
- let impl_type_scheme = tcx.lookup_item_type(impl_id);
-
- let prov = tcx.provided_trait_methods(trait_ref.def_id);
- for trait_method in &prov {
- // Synthesize an ID.
- let new_id = tcx.sess.next_node_id();
- let new_did = DefId::local(new_id);
-
- debug!("new_did={:?} trait_method={:?}", new_did, trait_method);
-
- // Create substitutions for the various trait parameters.
- let new_method_ty =
- Rc::new(subst_receiver_types_in_method_ty(
- tcx,
- impl_id,
- &impl_type_scheme,
- trait_ref,
- new_did,
- &**trait_method,
- Some(trait_method.def_id)));
-
- debug!("new_method_ty={:?}", new_method_ty);
- all_impl_items.push(MethodTraitItemId(new_did));
-
- // construct the polytype for the method based on the
- // method_ty. it will have all the generics from the
- // impl, plus its own.
- let new_polytype = ty::TypeScheme {
- generics: new_method_ty.generics.clone(),
- ty: tcx.mk_fn(Some(new_did),
- tcx.mk_bare_fn(new_method_ty.fty.clone()))
- };
- debug!("new_polytype={:?}", new_polytype);
-
- tcx.register_item_type(new_did, new_polytype);
- tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone());
- tcx.impl_or_trait_items
- .borrow_mut()
- .insert(new_did, ty::MethodTraitItem(new_method_ty));
-
- // Pair the new synthesized ID up with the
- // ID of the method.
- self.crate_context.tcx.provided_method_sources.borrow_mut()
- .insert(new_did, trait_method.def_id);
- }
- }
-
fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
match self.inherent_impls.borrow().get(&base_def_id) {
Some(implementation_list) => {
fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
match item.node {
ItemImpl(_, _, _, _, _, ref impl_items) => {
- let mut items: Vec<ImplOrTraitItemId> =
- impl_items.iter().map(|impl_item| {
+ impl_items.iter().map(|impl_item| {
+ let impl_def_id = self.crate_context.tcx.map.local_def_id(impl_item.id);
match impl_item.node {
hir::ConstImplItem(..) => {
- ConstTraitItemId(DefId::local(impl_item.id))
+ ConstTraitItemId(impl_def_id)
}
hir::MethodImplItem(..) => {
- MethodTraitItemId(DefId::local(impl_item.id))
+ MethodTraitItemId(impl_def_id)
}
hir::TypeImplItem(_) => {
- TypeTraitItemId(DefId::local(impl_item.id))
+ TypeTraitItemId(impl_def_id)
}
}
- }).collect();
-
- let def_id = DefId::local(item.id);
- if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(def_id) {
- self.instantiate_default_methods(def_id, &trait_ref, &mut items);
- }
-
- items
+ }).collect()
}
_ => {
self.crate_context.tcx.sess.span_bug(item.span,
}
_ => {
// Destructors only work on nominal types.
- if impl_did.is_local() {
- {
- match tcx.map.find(impl_did.node) {
- Some(hir_map::NodeItem(item)) => {
- span_err!(tcx.sess, item.span, E0120,
- "the Drop trait may only be implemented on structures");
- }
- _ => {
- tcx.sess.bug("didn't find impl in ast \
- map");
- }
+ if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
+ match tcx.map.find(impl_node_id) {
+ Some(hir_map::NodeItem(item)) => {
+ span_err!(tcx.sess, item.span, E0120,
+ "the Drop trait may only be implemented on structures");
+ }
+ _ => {
+ tcx.sess.bug("didn't find impl in ast \
+ map");
}
}
} else {
debug!("check_implementations_of_copy: impl_did={:?}",
impl_did);
- if impl_did.krate != LOCAL_CRATE {
+ let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+ n
+ } else {
debug!("check_implementations_of_copy(): impl not in this \
crate");
return
- }
+ };
let self_type = tcx.lookup_item_type(impl_did);
debug!("check_implementations_of_copy: self_type={:?} (bound)",
self_type);
- let span = tcx.map.span(impl_did.node);
- let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
+ let span = tcx.map.span(impl_node_id);
+ let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
let self_type = self_type.ty.subst(tcx, ¶m_env.free_substs);
assert!(!self_type.has_escaping_regions());
debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
impl_did);
- if impl_did.krate != LOCAL_CRATE {
+ let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
+ n
+ } else {
debug!("check_implementations_of_coerce_unsized(): impl not \
in this crate");
return;
- }
+ };
let source = tcx.lookup_item_type(impl_did).ty;
let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
source, target);
- let span = tcx.map.span(impl_did.node);
- let param_env = ParameterEnvironment::for_item(tcx, impl_did.node);
+ let span = tcx.map.span(impl_node_id);
+ let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
let source = source.subst(tcx, ¶m_env.free_substs);
let target = target.subst(tcx, ¶m_env.free_substs);
assert!(!source.has_escaping_regions());
let fields = &def_a.struct_variant().fields;
let diff_fields = fields.iter().enumerate().filter_map(|(i, f)| {
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
- if infcx.sub_types(false, origin, b, a).is_ok() {
+
+ if f.unsubst_ty().is_phantom_data() {
+ // Ignore PhantomData fields
+ None
+ } else if infcx.sub_types(false, origin, b, a).is_ok() {
+ // Ignore fields that aren't significantly changed
None
} else {
+ // Collect up all fields that were significantly changed
+ // i.e. those that contain T in coerce_unsized T -> U
Some((i, a, b))
}
}).collect::<Vec<_>>();
let mut fulfill_cx = infcx.fulfillment_cx.borrow_mut();
// Register an obligation for `A: Trait<B>`.
- let cause = traits::ObligationCause::misc(span, impl_did.node);
+ let cause = traits::ObligationCause::misc(span, impl_node_id);
let predicate = traits::predicate_for_trait_def(tcx, cause, trait_def_id,
0, source, vec![target]);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(tcx, &infcx.parameter_environment
.caller_bounds);
- infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node);
+ infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
if let Some(kind) = kind {
tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
"add `#![feature(unboxed_closures)]` to the crate attributes to enable");
}
-fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
- impl_id: DefId,
- impl_type_scheme: &ty::TypeScheme<'tcx>,
- trait_ref: &ty::TraitRef<'tcx>,
- new_def_id: DefId,
- method: &ty::Method<'tcx>,
- provided_source: Option<DefId>)
- -> ty::Method<'tcx>
-{
- let combined_substs = tcx.make_substs_for_receiver_types(trait_ref, method);
-
- debug!("subst_receiver_types_in_method_ty: combined_substs={:?}",
- combined_substs);
-
- let method_predicates = method.predicates.subst(tcx, &combined_substs);
- let mut method_generics = method.generics.subst(tcx, &combined_substs);
-
- // replace the type parameters declared on the trait with those
- // from the impl
- for &space in &[subst::TypeSpace, subst::SelfSpace] {
- method_generics.types.replace(
- space,
- impl_type_scheme.generics.types.get_slice(space).to_vec());
- method_generics.regions.replace(
- space,
- impl_type_scheme.generics.regions.get_slice(space).to_vec());
- }
-
- debug!("subst_receiver_types_in_method_ty: method_generics={:?}",
- method_generics);
-
- let method_fty = method.fty.subst(tcx, &combined_substs);
-
- debug!("subst_receiver_types_in_method_ty: method_ty={:?}",
- method.fty);
-
- ty::Method::new(
- method.name,
- method_generics,
- method_predicates,
- method_fty,
- method.explicit_self,
- method.vis,
- new_def_id,
- ImplContainer(impl_id),
- provided_source
- )
-}
-
pub fn check_coherence(crate_context: &CrateCtxt) {
CoherenceChecker {
crate_context: crate_context,
//! Orphan checker: every impl either implements a trait defined in this
//! crate or pertains to a type defined in this crate.
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
use middle::traits;
use middle::ty;
+use syntax::ast;
use syntax::codemap::Span;
use rustc_front::visit;
use rustc_front::hir;
/// to prevent inundating the user with a bunch of similar error
/// reports.
fn check_item(&self, item: &hir::Item) {
- let def_id = DefId::local(item.id);
+ let def_id = self.tcx.map.local_def_id(item.id);
match item.node {
hir::ItemImpl(_, _, _, None, _, _) => {
// For inherent impls, self type must be a nominal type
"*mut T",
item.span);
}
- ty::TyInt(hir::TyI8) => {
+ ty::TyInt(ast::TyI8) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i8_impl(),
"i8",
"i8",
item.span);
}
- ty::TyInt(hir::TyI16) => {
+ ty::TyInt(ast::TyI16) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i16_impl(),
"i16",
"i16",
item.span);
}
- ty::TyInt(hir::TyI32) => {
+ ty::TyInt(ast::TyI32) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i32_impl(),
"i32",
"i32",
item.span);
}
- ty::TyInt(hir::TyI64) => {
+ ty::TyInt(ast::TyI64) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.i64_impl(),
"i64",
"i64",
item.span);
}
- ty::TyInt(hir::TyIs) => {
+ ty::TyInt(ast::TyIs) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.isize_impl(),
"isize",
"isize",
item.span);
}
- ty::TyUint(hir::TyU8) => {
+ ty::TyUint(ast::TyU8) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u8_impl(),
"u8",
"u8",
item.span);
}
- ty::TyUint(hir::TyU16) => {
+ ty::TyUint(ast::TyU16) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u16_impl(),
"u16",
"u16",
item.span);
}
- ty::TyUint(hir::TyU32) => {
+ ty::TyUint(ast::TyU32) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u32_impl(),
"u32",
"u32",
item.span);
}
- ty::TyUint(hir::TyU64) => {
+ ty::TyUint(ast::TyU64) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.u64_impl(),
"u64",
"u64",
item.span);
}
- ty::TyUint(hir::TyUs) => {
+ ty::TyUint(ast::TyUs) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.usize_impl(),
"usize",
"usize",
item.span);
}
- ty::TyFloat(hir::TyF32) => {
+ ty::TyFloat(ast::TyF32) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.f32_impl(),
"f32",
"f32",
item.span);
}
- ty::TyFloat(hir::TyF64) => {
+ ty::TyFloat(ast::TyF64) => {
self.check_primitive_impl(def_id,
self.tcx.lang_items.f64_impl(),
"f64",
//! Overlap: No two impls for the same trait are implemented for the
//! same type.
-use middle::def_id::{DefId, LOCAL_CRATE};
+use metadata::cstore::LOCAL_CRATE;
+use middle::def_id::DefId;
use middle::traits;
use middle::ty;
use middle::infer::{self, new_infer_ctxt};
}
} else if impl2_def_id.krate != LOCAL_CRATE {
Some((impl1_def_id, impl2_def_id))
- } else if impl1_def_id.node < impl2_def_id.node {
+ } else if impl1_def_id < impl2_def_id {
Some((impl1_def_id, impl2_def_id))
} else {
Some((impl2_def_id, impl1_def_id))
}
fn span_of_impl(&self, impl_did: DefId) -> Span {
- assert_eq!(impl_did.krate, LOCAL_CRATE);
- self.tcx.map.span(impl_did.node)
+ let node_id = self.tcx.map.as_local_node_id(impl_did).unwrap();
+ self.tcx.map.span(node_id)
}
}
// look for another default impl; note that due to the
// general orphan/coherence rules, it must always be
// in this crate.
- let impl_def_id = DefId::local(item.id);
+ let impl_def_id = self.tcx.map.local_def_id(item.id);
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
match prev_default_impl {
Some(prev_id) => {
self.report_overlap_error(trait_ref.def_id,
impl_def_id,
- DefId::local(prev_id));
+ self.tcx.map.local_def_id(prev_id));
}
None => { }
}
}
hir::ItemImpl(_, _, _, Some(_), ref self_ty, _) => {
- let impl_def_id = DefId::local(item.id);
+ let impl_def_id = self.tcx.map.local_def_id(item.id);
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_def_id = trait_ref.def_id;
match trait_ref.self_ty().sty {
//! Unsafety checker: every impl either implements a trait defined in this
//! crate or pertains to a type defined in this crate.
-use middle::def_id::DefId;
use middle::ty;
use rustc_front::visit;
use rustc_front::hir;
fn check_unsafety_coherence(&mut self, item: &'v hir::Item,
unsafety: hir::Unsafety,
polarity: hir::ImplPolarity) {
- match self.tcx.impl_trait_ref(DefId::local(item.id)) {
+ match self.tcx.impl_trait_ref(self.tcx.map.local_def_id(item.id)) {
None => {
// Inherent impl.
match unsafety {
use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
use middle::def;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
use middle::free_region::FreeRegionMap;
use syntax::abi;
use syntax::ast;
+use syntax::attr;
use syntax::codemap::Span;
use syntax::parse::token::special_idents;
use syntax::ptr::P;
use rustc_front::hir;
use rustc_front::visit;
-use rustc_front::attr;
use rustc_front::print::pprust;
///////////////////////////////////////////////////////////////////////////
}
fn method_ty(&self, method_id: ast::NodeId) -> Rc<ty::Method<'tcx>> {
- let def_id = DefId::local(method_id);
+ let def_id = self.tcx.map.local_def_id(method_id);
match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
ty::MethodTraitItem(ref mty) => mty.clone(),
_ => {
{
let tcx = self.tcx;
- if trait_id.krate != LOCAL_CRATE {
- return tcx.lookup_trait_def(trait_id)
- }
-
- let item = match tcx.map.get(trait_id.node) {
- hir_map::NodeItem(item) => item,
- _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id))
- };
+ if let Some(trait_id) = tcx.map.as_local_node_id(trait_id) {
+ let item = match tcx.map.get(trait_id) {
+ hir_map::NodeItem(item) => item,
+ _ => tcx.sess.bug(&format!("get_trait_def({:?}): not an item", trait_id))
+ };
- trait_def_of_item(self, &*item)
+ trait_def_of_item(self, &*item)
+ } else {
+ tcx.lookup_trait_def(trait_id)
+ }
}
/// Ensure that the (transitive) super predicates for
assoc_name: ast::Name)
-> bool
{
- if trait_def_id.is_local() {
- trait_defines_associated_type_named(self.ccx, trait_def_id.node, assoc_name)
+ if let Some(trait_id) = self.tcx().map.as_local_node_id(trait_def_id) {
+ trait_defines_associated_type_named(self.ccx, trait_id, assoc_name)
} else {
let trait_def = self.tcx().lookup_trait_def(trait_def_id);
trait_def.associated_type_names.contains(&assoc_name)
/// Find bounds from hir::Generics. This requires scanning through the
/// AST. We do this to avoid having to convert *all* the bounds, which
/// would create artificial cycles. Instead we can only convert the
-/// bounds for those a type parameter `X` if `X::Foo` is used.
+/// bounds for a type parameter `X` if `X::Foo` is used.
impl<'tcx> GetTypeParameterBounds<'tcx> for hir::Generics {
fn get_type_parameter_bounds(&self,
astconv: &AstConv<'tcx>,
let path_res = *tcx.def_map.borrow().get(&ast_ty.id).unwrap();
match path_res.base_def {
def::DefSelfTy(Some(def_id), None) => {
- path_res.depth == 0 && def_id.node == param_id
+ path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
}
def::DefTyParam(_, _, def_id, _) => {
- path_res.depth == 0 && def_id == DefId::local(param_id)
+ path_res.depth == 0 && def_id == tcx.map.local_def_id(param_id)
}
_ => {
false
container: ImplOrTraitItemContainer,
sig: &hir::MethodSig,
id: ast::NodeId,
- ident: ast::Ident,
+ name: ast::Name,
vis: hir::Visibility,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
astconv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
sig, untransformed_rcvr_ty);
- let def_id = DefId::local(id);
- let ty_method = ty::Method::new(ident.name,
+ let def_id = ccx.tcx.map.local_def_id(id);
+ let ty_method = ty::Method::new(name,
ty_generics,
ty_generic_predicates,
fty,
explicit_self_category,
vis,
def_id,
- container,
- None);
+ container);
let fty = ccx.tcx.mk_fn(Some(def_id),
ccx.tcx.mk_bare_fn(ty_method.fty.clone()));
debug!("method {} (id {}) has type {:?}",
- ident, id, fty);
+ name, id, fty);
ccx.tcx.register_item_type(def_id, TypeScheme {
generics: ty_method.generics.clone(),
ty: fty
write_ty_to_tcx(ccx.tcx, v.node.id, tt);
/* add the field to the tcache */
- ccx.tcx.register_item_type(DefId::local(v.node.id),
+ ccx.tcx.register_item_type(ccx.tcx.map.local_def_id(v.node.id),
ty::TypeScheme {
generics: struct_generics.clone(),
ty: tt
});
- ccx.tcx.predicates.borrow_mut().insert(DefId::local(v.node.id),
+ ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(v.node.id),
struct_predicates.clone());
}
fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
- ident: ast::Ident,
+ name: ast::Name,
id: ast::NodeId,
vis: hir::Visibility,
ty: ty::Ty<'tcx>,
- default: Option<&hir::Expr>)
+ has_value: bool)
{
- ccx.tcx.predicates.borrow_mut().insert(DefId::local(id),
+ ccx.tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(id),
ty::GenericPredicates::empty());
write_ty_to_tcx(ccx.tcx, id, ty);
- let default_id = default.map(|expr| DefId::local(expr.id));
let associated_const = Rc::new(ty::AssociatedConst {
- name: ident.name,
+ name: name,
vis: vis,
- def_id: DefId::local(id),
+ def_id: ccx.tcx.map.local_def_id(id),
container: container,
ty: ty,
- default: default_id,
+ has_value: has_value
});
ccx.tcx.impl_or_trait_items.borrow_mut()
- .insert(DefId::local(id), ty::ConstTraitItem(associated_const));
+ .insert(ccx.tcx.map.local_def_id(id), ty::ConstTraitItem(associated_const));
}
fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
- ident: ast::Ident,
+ name: ast::Name,
id: ast::NodeId,
vis: hir::Visibility,
ty: Option<Ty<'tcx>>)
{
let associated_type = Rc::new(ty::AssociatedType {
- name: ident.name,
+ name: name,
vis: vis,
ty: ty,
- def_id: DefId::local(id),
+ def_id: ccx.tcx.map.local_def_id(id),
container: container
});
ccx.tcx.impl_or_trait_items.borrow_mut()
- .insert(DefId::local(id), ty::TypeTraitItem(associated_type));
+ .insert(ccx.tcx.map.local_def_id(id), ty::TypeTraitItem(associated_type));
}
fn convert_methods<'a,'tcx,'i,I>(ccx: &CrateCtxt<'a, 'tcx>,
untransformed_rcvr_ty: Ty<'tcx>,
rcvr_ty_generics: &ty::Generics<'tcx>,
rcvr_ty_predicates: &ty::GenericPredicates<'tcx>)
- where I: Iterator<Item=(&'i hir::MethodSig, ast::NodeId, ast::Ident, hir::Visibility, Span)>
+ where I: Iterator<Item=(&'i hir::MethodSig, ast::NodeId, ast::Name, hir::Visibility, Span)>
{
debug!("convert_methods(untransformed_rcvr_ty={:?}, rcvr_ty_generics={:?}, \
rcvr_ty_predicates={:?})",
rcvr_ty_generics,
rcvr_ty_predicates);
- for (sig, id, ident, vis, _span) in methods {
+ for (sig, id, name, vis, _span) in methods {
convert_method(ccx,
container,
sig,
id,
- ident,
+ name,
vis,
untransformed_rcvr_ty,
rcvr_ty_generics,
fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
let tcx = ccx.tcx;
- debug!("convert: item {} with id {}", it.ident, it.id);
+ debug!("convert: item {} with id {}", it.name, it.id);
match it.node {
// These don't define types.
hir::ItemExternCrate(_) | hir::ItemUse(_) |
let (scheme, predicates) = convert_typed_item(ccx, it);
write_ty_to_tcx(tcx, it.id, scheme.ty);
convert_enum_variant_types(ccx,
- tcx.lookup_adt_def_master(DefId::local(it.id)),
+ tcx.lookup_adt_def_master(ccx.tcx.map.local_def_id(it.id)),
scheme,
predicates,
&enum_definition.variants);
tcx.record_trait_has_default_impl(trait_ref.def_id);
- tcx.impl_trait_refs.borrow_mut().insert(DefId::local(it.id), Some(trait_ref));
+ tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
+ Some(trait_ref));
}
hir::ItemImpl(_, _,
ref generics,
let selfty = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, &**selfty);
write_ty_to_tcx(tcx, it.id, selfty);
- tcx.register_item_type(DefId::local(it.id),
+ tcx.register_item_type(ccx.tcx.map.local_def_id(it.id),
TypeScheme { generics: ty_generics.clone(),
ty: selfty });
- tcx.predicates.borrow_mut().insert(DefId::local(it.id),
+ tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
ty_predicates.clone());
if let &Some(ref ast_trait_ref) = opt_trait_ref {
tcx.impl_trait_refs.borrow_mut().insert(
- DefId::local(it.id),
+ ccx.tcx.map.local_def_id(it.id),
Some(astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
&ExplicitRscope,
ast_trait_ref,
Some(selfty)))
);
} else {
- tcx.impl_trait_refs.borrow_mut().insert(DefId::local(it.id), None);
+ tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id), None);
}
hir::TypeImplItem(_) => &mut seen_type_items,
_ => &mut seen_value_items,
};
- if !seen_items.insert(impl_item.ident.name) {
+ if !seen_items.insert(impl_item.name) {
let desc = match impl_item.node {
hir::ConstImplItem(_, _) => "associated constant",
hir::TypeImplItem(_) => "associated type",
span_err!(tcx.sess, impl_item.span, E0201, "duplicate {}", desc);
}
- if let hir::ConstImplItem(ref ty, ref expr) = impl_item.node {
+ if let hir::ConstImplItem(ref ty, _) = impl_item.node {
let ty = ccx.icx(&ty_predicates)
.to_ty(&ExplicitRscope, &*ty);
- tcx.register_item_type(DefId::local(impl_item.id),
+ tcx.register_item_type(ccx.tcx.map.local_def_id(impl_item.id),
TypeScheme {
generics: ty_generics.clone(),
ty: ty,
});
- convert_associated_const(ccx, ImplContainer(DefId::local(it.id)),
- impl_item.ident, impl_item.id,
+ convert_associated_const(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)),
+ impl_item.name, impl_item.id,
impl_item.vis.inherit_from(parent_visibility),
- ty, Some(&*expr));
+ ty, true /* has_value */);
}
}
let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
- convert_associated_type(ccx, ImplContainer(DefId::local(it.id)),
- impl_item.ident, impl_item.id, impl_item.vis,
+ convert_associated_type(ccx, ImplContainer(ccx.tcx.map.local_def_id(it.id)),
+ impl_item.name, impl_item.id, impl_item.vis,
Some(typ));
}
}
// { fn foo(); }` is public, but private in `impl { fn
// foo(); }`).
let method_vis = ii.vis.inherit_from(parent_visibility);
- Some((sig, ii.id, ii.ident, method_vis, ii.span))
+ Some((sig, ii.id, ii.name, method_vis, ii.span))
} else {
None
}
});
convert_methods(ccx,
- ImplContainer(DefId::local(it.id)),
+ ImplContainer(ccx.tcx.map.local_def_id(it.id)),
methods,
selfty,
&ty_generics,
enforce_impl_params_are_constrained(tcx,
generics,
- DefId::local(it.id),
+ ccx.tcx.map.local_def_id(it.id),
impl_items);
},
hir::ItemTrait(_, _, _, ref trait_items) => {
let trait_def = trait_def_of_item(ccx, it);
let _: Result<(), ErrorReported> = // any error is already reported, can ignore
- ccx.ensure_super_predicates(it.span, DefId::local(it.id));
+ ccx.ensure_super_predicates(it.span, ccx.tcx.map.local_def_id(it.id));
convert_trait_predicates(ccx, it);
- let trait_predicates = tcx.lookup_predicates(DefId::local(it.id));
+ let trait_predicates = tcx.lookup_predicates(ccx.tcx.map.local_def_id(it.id));
debug!("convert: trait_bounds={:?}", trait_predicates);
hir::ConstTraitItem(ref ty, ref default) => {
let ty = ccx.icx(&trait_predicates)
.to_ty(&ExplicitRscope, ty);
- tcx.register_item_type(DefId::local(trait_item.id),
+ tcx.register_item_type(ccx.tcx.map.local_def_id(trait_item.id),
TypeScheme {
generics: trait_def.generics.clone(),
ty: ty,
});
- convert_associated_const(ccx, TraitContainer(DefId::local(it.id)),
- trait_item.ident, trait_item.id,
- hir::Public, ty, default.as_ref().map(|d| &**d));
+ convert_associated_const(ccx,
+ TraitContainer(ccx.tcx.map.local_def_id(it.id)),
+ trait_item.name,
+ trait_item.id,
+ hir::Public,
+ ty,
+ default.is_some())
}
_ => {}
}
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
});
- convert_associated_type(ccx, TraitContainer(DefId::local(it.id)),
- trait_item.ident, trait_item.id, hir::Public,
+ convert_associated_type(ccx,
+ TraitContainer(ccx.tcx.map.local_def_id(it.id)),
+ trait_item.name,
+ trait_item.id,
+ hir::Public,
typ);
}
_ => {}
hir::MethodTraitItem(ref sig, _) => sig,
_ => return None,
};
- Some((sig, ti.id, ti.ident, hir::Inherited, ti.span))
+ Some((sig, ti.id, ti.name, hir::Inherited, ti.span))
});
// Run convert_methods on the trait methods.
convert_methods(ccx,
- TraitContainer(DefId::local(it.id)),
+ TraitContainer(ccx.tcx.map.local_def_id(it.id)),
methods,
tcx.mk_self_type(),
&trait_def.generics,
// Add an entry mapping
let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
- let def_id = DefId::local(trait_item.id);
+ let def_id = ccx.tcx.map.local_def_id(trait_item.id);
match trait_item.node {
hir::ConstTraitItem(..) => {
ty::ConstTraitItemId(def_id)
}
}
}).collect());
- tcx.trait_item_def_ids.borrow_mut().insert(DefId::local(it.id), trait_item_def_ids);
+ tcx.trait_item_def_ids.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
+ trait_item_def_ids);
// This must be done after `collect_trait_methods` so that
// we have a method type stored for every method.
let (scheme, predicates) = convert_typed_item(ccx, it);
write_ty_to_tcx(tcx, it.id, scheme.ty);
- let variant = tcx.lookup_adt_def_master(DefId::local(it.id)).struct_variant();
+ let it_def_id = ccx.tcx.map.local_def_id(it.id);
+ let variant = tcx.lookup_adt_def_master(it_def_id).struct_variant();
- for (f, ty_f) in struct_def.fields.iter().zip(variant.fields.iter()) {
+ for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) {
convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
}
- if let Some(ctor_id) = struct_def.ctor_id {
- convert_variant_ctor(tcx, ctor_id, variant, scheme, predicates);
+ if !struct_def.is_struct() {
+ convert_variant_ctor(tcx, struct_def.id(), variant, scheme, predicates);
}
},
hir::ItemTy(_, ref generics) => {
scheme: ty::TypeScheme<'tcx>,
predicates: ty::GenericPredicates<'tcx>) {
let ctor_ty = match variant.kind() {
- VariantKind::Unit | VariantKind::Dict => scheme.ty,
+ VariantKind::Unit | VariantKind::Struct => scheme.ty,
VariantKind::Tuple => {
let inputs: Vec<_> =
variant.fields
.iter()
.map(|field| field.unsubst_ty())
.collect();
- tcx.mk_ctor_fn(DefId::local(ctor_id),
+ tcx.mk_ctor_fn(tcx.map.local_def_id(ctor_id),
&inputs[..],
scheme.ty)
}
};
write_ty_to_tcx(tcx, ctor_id, ctor_ty);
- tcx.predicates.borrow_mut().insert(DefId::local(ctor_id), predicates);
- tcx.register_item_type(DefId::local(ctor_id),
+ tcx.predicates.borrow_mut().insert(tcx.map.local_def_id(ctor_id), predicates);
+ tcx.register_item_type(tcx.map.local_def_id(ctor_id),
TypeScheme {
generics: scheme.generics,
ty: ctor_ty
scheme: ty::TypeScheme<'tcx>,
predicates: ty::GenericPredicates<'tcx>,
variants: &[P<hir::Variant>]) {
- let tcx = ccx.tcx;
- let icx = ccx.icx(&predicates);
-
// fill the field types
for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) {
- match variant.node.kind {
- hir::TupleVariantKind(ref args) => {
- let rs = ExplicitRscope;
- let input_tys: Vec<_> = args.iter().map(|va| icx.to_ty(&rs, &*va.ty)).collect();
- for (field, &ty) in ty_variant.fields.iter().zip(input_tys.iter()) {
- field.fulfill_ty(ty);
- }
- }
-
- hir::StructVariantKind(ref struct_def) => {
- for (f, ty_f) in struct_def.fields.iter().zip(ty_variant.fields.iter()) {
- convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
- }
- }
- };
+ for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) {
+ convert_field(ccx, &scheme.generics, &predicates, f, ty_f)
+ }
// Convert the ctor, if any. This also registers the variant as
// an item.
convert_variant_ctor(
- tcx,
- variant.node.id,
+ ccx.tcx,
+ variant.node.data.id(),
ty_variant,
scheme.clone(),
predicates.clone()
did: DefId,
name: ast::Name,
disr_val: ty::Disr,
- def: &hir::StructDef) -> ty::VariantDefData<'tcx, 'tcx> {
+ def: &hir::VariantData) -> ty::VariantDefData<'tcx, 'tcx> {
let mut seen_fields: FnvHashMap<ast::Name, Span> = FnvHashMap();
- let fields = def.fields.iter().map(|f| {
- let fid = DefId::local(f.node.id);
+ let fields = def.fields().iter().map(|f| {
+ let fid = tcx.map.local_def_id(f.node.id);
match f.node.kind {
- hir::NamedField(ident, vis) => {
- let dup_span = seen_fields.get(&ident.name).cloned();
+ hir::NamedField(name, vis) => {
+ let dup_span = seen_fields.get(&name).cloned();
if let Some(prev_span) = dup_span {
span_err!(tcx.sess, f.span, E0124,
"field `{}` is already declared",
- ident.name);
+ name);
span_note!(tcx.sess, prev_span, "previously declared here");
} else {
- seen_fields.insert(ident.name, f.span);
+ seen_fields.insert(name, f.span);
}
- ty::FieldDefData::new(fid, ident.name, vis)
+ ty::FieldDefData::new(fid, name, vis)
},
hir::UnnamedField(vis) => {
ty::FieldDefData::new(fid, special_idents::unnamed_field.name, vis)
fn convert_struct_def<'tcx>(tcx: &ty::ctxt<'tcx>,
it: &hir::Item,
- def: &hir::StructDef)
+ def: &hir::VariantData)
-> ty::AdtDefMaster<'tcx>
{
- let did = DefId::local(it.id);
+ let did = tcx.map.local_def_id(it.id);
+ let ctor_id = if !def.is_struct() {
+ tcx.map.local_def_id(def.id())
+ } else {
+ did
+ };
tcx.intern_adt_def(
did,
ty::AdtKind::Struct,
- vec![convert_struct_variant(tcx, did, it.ident.name, 0, def)]
+ vec![convert_struct_variant(tcx, ctor_id, it.name, 0, def)]
)
}
debug!("disr expr, checking {}", pprust::expr_to_string(e));
let hint = UncheckedExprHint(repr_ty);
- match const_eval::eval_const_expr_partial(tcx, e, hint) {
+ match const_eval::eval_const_expr_partial(tcx, e, hint, None) {
Ok(ConstVal::Int(val)) => Some(val as ty::Disr),
Ok(ConstVal::Uint(val)) => Some(val as ty::Disr),
Ok(_) => {
None
},
Err(err) => {
- span_err!(tcx.sess, err.span, E0080,
- "constant evaluation error: {}",
- err.description());
+ span_err!(tcx.sess, err.span, E0080,
+ "constant evaluation error: {}",
+ err.description());
+ if !e.span.contains(err.span) {
+ tcx.sess.span_note(e.span, "for enum discriminant here");
+ }
None
}
}
if let Some(prev_disr_val) = prev_disr_val {
let result = repr_type.disr_incr(prev_disr_val);
if let None = result {
- report_discrim_overflow(tcx, v.span, &v.node.name.name.as_str(),
+ report_discrim_overflow(tcx, v.span, &v.node.name.as_str(),
repr_type, prev_disr_val);
}
result
disr: ty::Disr)
-> ty::VariantDefData<'tcx, 'tcx>
{
- let did = DefId::local(v.node.id);
- let name = v.node.name.name;
- match v.node.kind {
- hir::TupleVariantKind(ref va) => {
- ty::VariantDefData {
- did: did,
- name: name,
- disr_val: disr,
- fields: va.iter().map(|&hir::VariantArg { id, .. }| {
- ty::FieldDefData::new(
- DefId::local(id),
- special_idents::unnamed_field.name,
- hir::Visibility::Public
- )
- }).collect()
- }
- }
- hir::StructVariantKind(ref def) => {
- convert_struct_variant(tcx, did, name, disr, &def)
- }
- }
+ let did = tcx.map.local_def_id(v.node.data.id());
+ let name = v.node.name;
+ convert_struct_variant(tcx, did, name, disr, &v.node.data)
}
- let did = DefId::local(it.id);
+ let did = tcx.map.local_def_id(it.id);
let repr_hints = tcx.lookup_repr_hints(did);
let (repr_type, repr_type_ty) = tcx.enum_repr_type(repr_hints.get(0));
let mut prev_disr = None;
prev_disr = Some(disr);
v
}).collect();
- tcx.intern_adt_def(DefId::local(it.id), ty::AdtKind::Enum, variants)
+ tcx.intern_adt_def(tcx.map.local_def_id(it.id), ty::AdtKind::Enum, variants)
}
/// Ensures that the super-predicates of the trait with def-id
debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
- if trait_def_id.krate != LOCAL_CRATE {
+ let trait_node_id = if let Some(n) = tcx.map.as_local_node_id(trait_def_id) {
+ n
+ } else {
// If this trait comes from an external crate, then all of the
// supertraits it may depend on also must come from external
// crates, and hence all of them already have their
// super-predicates "converted" (and available from crate
// meta-data), so there is no need to transitively test them.
return Vec::new();
- }
+ };
let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned();
let superpredicates = superpredicates.unwrap_or_else(|| {
- let trait_node_id = trait_def_id.node;
-
let item = match ccx.tcx.map.get(trait_node_id) {
hir_map::NodeItem(item) => item,
_ => ccx.tcx.sess.bug(&format!("trait_node_id {} is not an item", trait_node_id))
predicates: VecPerParamSpace::new(superbounds, vec![], vec![])
};
debug!("superpredicates for trait {:?} = {:?}",
- DefId::local(item.id),
+ tcx.map.local_def_id(item.id),
superpredicates);
tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
it: &hir::Item)
-> &'tcx ty::TraitDef<'tcx>
{
- let def_id = DefId::local(it.id);
+ let def_id = ccx.tcx.map.local_def_id(it.id);
let tcx = ccx.tcx;
if let Some(def) = tcx.trait_defs.borrow().get(&def_id) {
let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| {
match trait_item.node {
- hir::TypeTraitItem(..) => Some(trait_item.ident.name),
+ hir::TypeTraitItem(..) => Some(trait_item.name),
_ => None,
}
}).collect();
.iter()
.enumerate()
.map(|(i, def)| ty::ReEarlyBound(ty::EarlyBoundRegion {
- param_id: def.lifetime.id,
+ def_id: tcx.map.local_def_id(def.lifetime.id),
space: TypeSpace,
index: i as u32,
name: def.lifetime.name
.iter()
.enumerate()
.map(|(i, def)| tcx.mk_param(TypeSpace,
- i as u32, def.ident.name))
+ i as u32, def.name))
.collect();
// ...and also create the `Self` parameter.
trait_items.iter().any(|trait_item| {
match trait_item.node {
- hir::TypeTraitItem(..) => trait_item.ident.name == assoc_name,
+ hir::TypeTraitItem(..) => trait_item.name == assoc_name,
_ => false,
}
})
let tcx = ccx.tcx;
let trait_def = trait_def_of_item(ccx, it);
- let def_id = DefId::local(it.id);
+ let def_id = ccx.tcx.map.local_def_id(it.id);
let (generics, items) = match it.node {
hir::ItemTrait(_, ref generics, _, ref items) => (generics, items),
};
let assoc_ty = ccx.tcx.mk_projection(self_trait_ref,
- trait_item.ident.name);
+ trait_item.name);
let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)),
assoc_ty,
def_id: DefId)
-> ty::TypeScheme<'tcx>
{
- if def_id.krate != LOCAL_CRATE {
- return ccx.tcx.lookup_item_type(def_id);
- }
-
- match ccx.tcx.map.find(def_id.node) {
- Some(hir_map::NodeItem(item)) => {
- type_scheme_of_item(ccx, &*item)
- }
- Some(hir_map::NodeForeignItem(foreign_item)) => {
- let abi = ccx.tcx.map.get_foreign_abi(def_id.node);
- type_scheme_of_foreign_item(ccx, &*foreign_item, abi)
- }
- x => {
- ccx.tcx.sess.bug(&format!("unexpected sort of node \
- in get_item_type_scheme(): {:?}",
- x));
+ if let Some(node_id) = ccx.tcx.map.as_local_node_id(def_id) {
+ match ccx.tcx.map.find(node_id) {
+ Some(hir_map::NodeItem(item)) => {
+ type_scheme_of_item(ccx, &*item)
+ }
+ Some(hir_map::NodeForeignItem(foreign_item)) => {
+ let abi = ccx.tcx.map.get_foreign_abi(node_id);
+ type_scheme_of_foreign_item(ccx, &*foreign_item, abi)
+ }
+ x => {
+ ccx.tcx.sess.bug(&format!("unexpected sort of node \
+ in get_item_type_scheme(): {:?}",
+ x));
+ }
}
+ } else {
+ ccx.tcx.lookup_item_type(def_id)
}
}
-> ty::TypeScheme<'tcx>
{
memoized(&ccx.tcx.tcache,
- DefId::local(it.id),
+ ccx.tcx.map.local_def_id(it.id),
|_| compute_type_scheme_of_item(ccx, it))
}
hir::ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
let ty_generics = ty_generics_for_fn(ccx, generics, &ty::Generics::empty());
let tofd = astconv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &**decl);
- let ty = tcx.mk_fn(Some(DefId::local(it.id)), tcx.mk_bare_fn(tofd));
+ let ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(it.id)), tcx.mk_bare_fn(tofd));
ty::TypeScheme { ty: ty, generics: ty_generics }
}
hir::ItemTy(ref t, ref generics) => {
}
};
- let prev_predicates = tcx.predicates.borrow_mut().insert(DefId::local(it.id),
+ let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
predicates.clone());
assert!(prev_predicates.is_none());
// Debugging aid.
- if tcx.has_attr(DefId::local(it.id), "rustc_object_lifetime_default") {
+ if tcx.has_attr(ccx.tcx.map.local_def_id(it.id), "rustc_object_lifetime_default") {
let object_lifetime_default_reprs: String =
scheme.generics.types.iter()
.map(|t| match t.object_lifetime_default {
-> ty::TypeScheme<'tcx>
{
memoized(&ccx.tcx.tcache,
- DefId::local(it.id),
+ ccx.tcx.map.local_def_id(it.id),
|_| compute_type_scheme_of_foreign_item(ccx, it, abi))
}
}
};
- let prev_predicates = tcx.predicates.borrow_mut().insert(DefId::local(it.id), predicates);
+ let prev_predicates = tcx.predicates.borrow_mut().insert(ccx.tcx.map.local_def_id(it.id),
+ predicates);
assert!(prev_predicates.is_none());
}
-> ty::Generics<'tcx>
{
debug!("ty_generics_for_trait(trait_id={:?}, substs={:?})",
- DefId::local(trait_id), substs);
+ ccx.tcx.map.local_def_id(trait_id), substs);
let mut generics = ty_generics_for_type_or_impl(ccx, ast_generics);
space: SelfSpace,
index: 0,
name: special_idents::type_self.name,
- def_id: DefId::local(param_id),
- default_def_id: DefId::local(parent),
+ def_id: ccx.tcx.map.local_def_id(param_id),
+ default_def_id: ccx.tcx.map.local_def_id(parent),
default: None,
object_lifetime_default: ty::ObjectLifetimeDefault::BaseDefault,
};
// type parameter (e.g., `<T:Foo>`).
for (index, param) in ast_generics.ty_params.iter().enumerate() {
let index = index as u32;
- let param_ty = ty::ParamTy::new(space, index, param.ident.name).to_ty(ccx.tcx);
+ let param_ty = ty::ParamTy::new(space, index, param.name).to_ty(ccx.tcx);
let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)),
param_ty,
¶m.bounds,
let early_lifetimes = early_bound_lifetimes_from_generics(space, ast_generics);
for (index, param) in early_lifetimes.iter().enumerate() {
let index = index as u32;
+ let def_id = tcx.map.local_def_id(param.lifetime.id);
let region =
ty::ReEarlyBound(ty::EarlyBoundRegion {
- param_id: param.lifetime.id,
+ def_id: def_id,
space: space,
index: index,
name: param.lifetime.name
let def = ty::RegionParameterDef { name: l.lifetime.name,
space: space,
index: i as u32,
- def_id: DefId::local(l.lifetime.id),
+ def_id: ccx.tcx.map.local_def_id(l.lifetime.id),
bounds: bounds };
result.regions.push(space, def);
}
let def = ty::TypeParameterDef {
space: space,
index: index,
- name: param.ident.name,
- def_id: DefId::local(param.id),
- default_def_id: DefId::local(parent),
+ name: param.name,
+ def_id: ccx.tcx.map.local_def_id(param.id),
+ default_def_id: ccx.tcx.map.local_def_id(parent),
default: default,
object_lifetime_default: object_lifetime_default,
};
tcx.fold_regions(value, &mut false, |region, _| {
match region {
ty::ReEarlyBound(data) => {
- let def_id = DefId::local(data.param_id);
- ty::ReFree(ty::FreeRegion { scope: scope,
- bound_region: ty::BrNamed(def_id, data.name) })
+ ty::ReFree(ty::FreeRegion {
+ scope: scope,
+ bound_region: ty::BrNamed(data.def_id, data.name)
+ })
}
_ => region
}
for (index, ty_param) in ast_generics.ty_params.iter().enumerate() {
let param_ty = ty::ParamTy { space: TypeSpace,
idx: index as u32,
- name: ty_param.ident.name };
+ name: ty_param.name };
if !input_parameters.contains(&ctp::Parameter::Type(param_ty)) {
report_unused_parameter(tcx, ty_param.span, "type", ¶m_ty.to_string());
}
let lifetimes_in_associated_types: HashSet<_> =
impl_items.iter()
- .map(|item| tcx.impl_or_trait_item(DefId::local(item.id)))
+ .map(|item| tcx.impl_or_trait_item(tcx.map.local_def_id(item.id)))
.filter_map(|item| match item {
ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
.collect();
for (index, lifetime_def) in ast_generics.lifetimes.iter().enumerate() {
- let region = ty::EarlyBoundRegion { param_id: lifetime_def.lifetime.id,
+ let def_id = tcx.map.local_def_id(lifetime_def.lifetime.id);
+ let region = ty::EarlyBoundRegion { def_id: def_id,
space: TypeSpace,
index: index as u32,
name: lifetime_def.lifetime.name };
"##,
E0026: r##"
-This error indicates that a struct pattern attempted to extract a non-existant
+This error indicates that a struct pattern attempted to extract a non-existent
field from a struct. Struct fields are identified by the name used before the
colon `:` so struct patterns should resemble the declaration of the struct type
being matched.
"##,
E0101: r##"
-You hit this error because the compiler the compiler lacks information
-to determine a type for this expression. Erroneous code example:
+You hit this error because the compiler lacks the information to
+determine a type for this expression. Erroneous code example:
```
fn main() {
enum Bar<'a> { A(u8), B(&'a bool), } // correct
type MyStr = &str; // error
-type MyStr<'a> = &'a str; //correct
-
+type MyStr<'a> = &'a str; // correct
```
Lifetime elision is a special, limited kind of inference for lifetimes in
```
"##,
+E0163: r##"
+This error means that an attempt was made to match an enum variant as a
+struct type when the variant isn't a struct type:
+
+```
+enum Foo { B(u32) }
+
+fn bar(foo: Foo) -> u32 {
+ match foo {
+ Foo::B{i} => i // error 0163
+ }
+}
+```
+
+Try using `()` instead:
+
+```
+fn bar(foo: Foo) -> u32 {
+ match foo {
+ Foo::B(i) => i
+ }
+}
+```
+"##,
+
+E0164: r##"
+
+This error means that an attempt was made to match a struct type enum
+variant as a non-struct type:
+
+```
+enum Foo { B{ i: u32 } }
+
+fn bar(foo: Foo) -> u32 {
+ match foo {
+ Foo::B(i) => i // error 0164
+ }
+}
+```
+
+Try using `{}` instead:
+
+```
+fn bar(foo: Foo) -> u32 {
+ match foo {
+ Foo::B{i} => i
+ }
+}
+```
+"##,
+
+
E0166: r##"
This error means that the compiler found a return expression in a function
marked as diverging. A function diverges if it has `!` in the place of the
some types will not implement `Clone`, and thus will not get this method.
In our erroneous example, however, we're referencing a single concrete type.
-Since we know for certain that Wrapper<u32> implements Clone, there's no reason
-to also specify it in a `where` clause.
+Since we know for certain that `Wrapper<u32>` implements `Clone`, there's no
+reason to also specify it in a `where` clause.
"##,
E0194: r##"
"##,
E0211: r##"
-You used an intrinsic function which doesn't correspond to its
-definition. Erroneous code example:
+You used a function or type which doesn't fit the requirements for where it was
+used. Erroneous code examples:
```
#![feature(intrinsics)]
extern "rust-intrinsic" {
fn size_of<T>(); // error: intrinsic has wrong type
}
+
+// or:
+
+fn main() -> i32 { 0 }
+// error: main function expects type: `fn() {main}`: expected (), found i32
+
+// or:
+
+let x = 1u8;
+match x {
+ 0u8...3i8 => (),
+ // error: mismatched types in range: expected u8, found i8
+ _ => ()
+}
+
+// or:
+
+use std::rc::Rc;
+struct Foo;
+
+impl Foo {
+ fn x(self: Rc<Foo>) {}
+ // error: mismatched self type: expected `Foo`: expected struct
+ // `Foo`, found struct `alloc::rc::Rc`
+}
```
-Please check the function definition. Example:
+For the first code example, please check the function definition. Example:
```
#![feature(intrinsics)]
extern "rust-intrinsic" {
- fn size_of<T>() -> usize;
+ fn size_of<T>() -> usize; // ok!
+}
+```
+
+The second case example is a bit particular : the main function must always
+have this definition:
+
+```
+fn main();
+```
+
+They never take parameters and never return types.
+
+For the third example, when you match, all patterns must have the same type
+as the type you're matching on. Example:
+
+```
+let x = 1u8;
+match x {
+ 0u8...3u8 => (), // ok!
+ _ => ()
+}
+```
+
+And finally, for the last example, only `Box<Self>`, `&Self`, `Self`,
+or `&mut Self` work as explicit self parameters. Example:
+
+```
+struct Foo;
+
+impl Foo {
+ fn x(self: Box<Foo>) {} // ok!
}
```
"##,
do_something function. This is not legal: `Foo::Bar` is a value of type `Foo`,
not a distinct static type. Likewise, it's not legal to attempt to
`impl Foo::Bar`: instead, you must `impl Foo` and then pattern match to specify
-behaviour for specific enum variants.
+behavior for specific enum variants.
"##,
E0249: r##"
E0368: r##"
This error indicates that a binary assignment operator like `+=` or `^=` was
-applied to the wrong types. For example:
+applied to a type that doesn't support it. For example:
+
+```
+let mut x = 12f32; // error: binary operation `<<` cannot be applied to
+ // type `f32`
+x <<= 2;
```
-let mut x: u16 = 5;
-x ^= true; // error, `^=` cannot be applied to types `u16` and `bool`
-x += (); // error, `+=` cannot be applied to types `u16` and `()`
+
+To fix this error, please check that this type implements this binary
+operation. Example:
+
+```
+let x = 12u32; // the `u32` type does implement the `ShlAssign` trait
+
+x <<= 2; // ok!
```
+It is also possible to overload most operators for your own type by
+implementing the `[OP]Assign` traits from `std::ops`.
+
Another problem you might be facing is this: suppose you've overloaded the `+`
operator for some type `Foo` by implementing the `std::ops::Add` trait for
`Foo`, but you find that using `+=` does not work, as in this example:
fn main() {
let mut x: Foo = Foo(5);
- x += Foo(7); // error, `+= cannot be applied to types `Foo` and `Foo`
+ x += Foo(7); // error, `+= cannot be applied to the type `Foo`
}
```
-This is because the binary assignment operators currently do not work off of
-traits, so it is not possible to overload them. See [RFC 953] for a proposal
-to change this.
-
-[RFC 953]: https://github.com/rust-lang/rfcs/pull/953
+This is because `AddAssign` is not automatically implemented, so you need to
+manually implement it for your type.
"##,
E0369: r##"
```
"##,
+E0516: r##"
+The `typeof` keyword is currently reserved but unimplemented.
+Erroneous code example:
+
+```
+fn main() {
+ let x: typeof(92) = 92;
+}
+```
+
+Try using type inference instead. Example:
+
+```
+fn main() {
+ let x = 92;
+}
+```
+"##,
+
}
register_diagnostics! {
// E0129,
// E0141,
// E0159, // use of trait `{}` as struct constructor
- E0163,
- E0164,
E0167,
// E0168,
// E0173, // manual implementations of unboxed closure traits are experimental
E0182,
E0183,
// E0187, // can't infer the kind of the closure
-// E0188, // can not cast a immutable reference to a mutable pointer
+// E0188, // can not cast an immutable reference to a mutable pointer
// E0189, // deprecated: can only cast a boxed pointer to a boxed object
// E0190, // deprecated: can only cast a &-pointer to an &-object
E0196, // cannot determine a type for this closure
// type because its default value `{}` references the type `Self`"
E0399, // trait items need to be implemented because the associated
// type `{}` was overridden
- E0436, // functional record update requires a struct
+ E0436, // functional record update requires a struct
+ E0513 // no type for local variable ..
}
#![feature(iter_cmp)]
#![feature(iter_arith)]
#![feature(quote)]
-#![feature(ref_slice)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
-#![feature(slice_splits)]
#![feature(staged_api)]
#![feature(vec_push_all)]
#![feature(cell_extras)]
extern crate rustc;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_front;
+extern crate rustc_back;
+pub use rustc::front;
pub use rustc::lint;
pub use rustc::metadata;
pub use rustc::middle;
pub use rustc::session;
pub use rustc::util;
+use front::map as hir_map;
use middle::def;
-use middle::def_id::DefId;
use middle::infer;
use middle::subst;
use middle::ty::{self, Ty, HasTypeFlags};
use session::config;
use util::common::time;
-use rustc::front::map as hir_map;
use rustc_front::hir;
use syntax::codemap::Span;
}
_ => ()
}
- let se_ty = tcx.mk_fn(Some(DefId::local(main_id)), tcx.mk_bare_fn(ty::BareFnTy {
+ let main_def_id = tcx.map.local_def_id(main_id);
+ let se_ty = tcx.mk_fn(Some(main_def_id), tcx.mk_bare_fn(ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: abi::Rust,
sig: ty::Binder(ty::FnSig {
_ => ()
}
- let se_ty = tcx.mk_fn(Some(DefId::local(start_id)), tcx.mk_bare_fn(ty::BareFnTy {
+ let se_ty = tcx.mk_fn(Some(ccx.tcx.map.local_def_id(start_id)),
+ tcx.mk_bare_fn(ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: abi::Rust,
sig: ty::Binder(ty::FnSig {
use arena;
use arena::TypedArena;
-use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::def_id::DefId;
use middle::resolve_lifetime as rl;
use middle::subst;
use middle::subst::{ParamSpace, FnSpace, TypeSpace, SelfSpace, VecPerParamSpace};
];
- all.into_iter()
+ all.into_iter() // iterating over (Option<DefId>, Variance)
.filter(|&(ref d,_)| d.is_some())
- .filter(|&(ref d,_)| d.as_ref().unwrap().is_local())
- .map(|(d, v)| (d.unwrap().node, v))
+ .map(|(d, v)| (d.unwrap(), v)) // (DefId, Variance)
+ .filter_map(|(d, v)| tcx.map.as_local_node_id(d).map(|n| (n, v))) // (NodeId, Variance)
.collect()
}
// "invalid item id" from "item id with no
// parameters".
if self.num_inferred() == inferreds_on_entry {
+ let item_def_id = self.tcx.map.local_def_id(item_id);
let newly_added =
self.tcx.item_variance_map.borrow_mut().insert(
- DefId::local(item_id),
+ item_def_id,
self.empty_variances.clone()).is_none();
assert!(newly_added);
}
param_id={}, \
inf_index={:?}, \
initial_variance={:?})",
- self.tcx.item_path_str(DefId::local(item_id)),
+ self.tcx.item_path_str(self.tcx.map.local_def_id(item_id)),
item_id, kind, space, index, param_id, inf_index,
initial_variance);
}
impl<'a, 'tcx, 'v> Visitor<'v> for ConstraintContext<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
- let did = DefId::local(item.id);
let tcx = self.terms_cx.tcx;
+ let did = tcx.map.local_def_id(item.id);
debug!("visit_item item={}", tcx.map.node_to_string(item.id));
-> VarianceTermPtr<'a> {
assert_eq!(param_def_id.krate, item_def_id.krate);
- if param_def_id.is_local() {
+ if let Some(param_node_id) = self.tcx().map.as_local_node_id(param_def_id) {
// Parameter on an item defined within current crate:
// variance not yet inferred, so return a symbolic
// variance.
- let InferredIndex(index) = self.inferred_index(param_def_id.node);
+ let InferredIndex(index) = self.inferred_index(param_node_id);
self.terms_cx.inferred_infos[index].term
} else {
// Parameter on an item defined within another crate:
ty::TyParam(ref data) => {
let def_id = generics.types.get(data.space, data.idx as usize).def_id;
- assert_eq!(def_id.krate, LOCAL_CRATE);
- match self.terms_cx.inferred_map.get(&def_id.node) {
+ let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
+ match self.terms_cx.inferred_map.get(&node_id) {
Some(&index) => {
self.add_constraint(index, variance);
}
variance: VarianceTermPtr<'a>) {
match region {
ty::ReEarlyBound(ref data) => {
- if self.is_to_be_inferred(data.param_id) {
- let index = self.inferred_index(data.param_id);
+ let node_id = self.tcx().map.as_local_node_id(data.def_id).unwrap();
+ if self.is_to_be_inferred(node_id) {
+ let index = self.inferred_index(node_id);
self.add_constraint(index, variance);
}
}
item_id,
item_variances);
- let item_def_id = DefId::local(item_id);
+ let item_def_id = tcx.map.local_def_id(item_id);
// For unit testing: check for a special "rustc_variance"
// attribute and report an error with various results if found.
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for ToLowercase {
type Item = char;
- fn next(&mut self) -> Option<char> { self.0.next() }
+ fn next(&mut self) -> Option<char> {
+ self.0.next()
+ }
}
/// An iterator over the uppercase mapping of a given character, returned from
#[stable(feature = "rust1", since = "1.0.0")]
impl Iterator for ToUppercase {
type Item = char;
- fn next(&mut self) -> Option<char> { self.0.next() }
+ fn next(&mut self) -> Option<char> {
+ self.0.next()
+ }
}
Three(char, char, char),
Two(char, char),
One(char),
- Zero
+ Zero,
}
impl CaseMappingIter {
#[stable(feature = "rust1", since = "1.0.0")]
#[lang = "char"]
impl char {
- /// Checks if a `char` parses as a numeric digit in the given radix.
+ /// Checks if a `char` is a digit in the given radix.
+ ///
+ /// A 'radix' here is sometimes also called a 'base'. A radix of two
+ /// indicates a binary number, a radix of ten, decimal, and a radix of
+ /// sixteen, hexicdecimal, to give some common values. Arbitrary
+ /// radicum are supported.
///
/// Compared to `is_numeric()`, this function only recognizes the characters
/// `0-9`, `a-z` and `A-Z`.
///
- /// # Return value
+ /// 'Digit' is defined to be only the following characters:
///
- /// Returns `true` if `c` is a valid digit under `radix`, and `false`
- /// otherwise.
+ /// * `0-9`
+ /// * `a-z`
+ /// * `A-Z`
+ ///
+ /// For a more comprehensive understanding of 'digit', see [`is_numeric()`][is_numeric].
+ ///
+ /// [is_numeric]: #method.is_numeric
///
/// # Panics
///
- /// Panics if given a radix > 36.
+ /// Panics if given a radix larger than 36.
///
/// # Examples
///
+ /// Basic usage:
+ ///
/// ```
- /// let c = '1';
+ /// let d = '1';
///
- /// assert!(c.is_digit(10));
+ /// assert!(d.is_digit(10));
///
- /// assert!('f'.is_digit(16));
+ /// let d = 'f';
+ ///
+ /// assert!(d.is_digit(16));
+ /// assert!(!d.is_digit(10));
+ /// ```
+ ///
+ /// Passing a large radix, causing a panic:
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let result = thread::spawn(|| {
+ /// let d = '1';
+ ///
+ /// // this panics
+ /// d.is_digit(37);
+ /// }).join();
+ ///
+ /// assert!(result.is_err());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn is_digit(self, radix: u32) -> bool { C::is_digit(self, radix) }
+ pub fn is_digit(self, radix: u32) -> bool {
+ C::is_digit(self, radix)
+ }
- /// Converts a character to the corresponding digit.
+ /// Converts a `char` to a digit in the given radix.
+ ///
+ /// A 'radix' here is sometimes also called a 'base'. A radix of two
+ /// indicates a binary number, a radix of ten, decimal, and a radix of
+ /// sixteen, hexicdecimal, to give some common values. Arbitrary
+ /// radicum are supported.
+ ///
+ /// 'Digit' is defined to be only the following characters:
+ ///
+ /// * `0-9`
+ /// * `a-z`
+ /// * `A-Z`
///
- /// # Return value
+ /// # Failure
///
- /// If `c` is between '0' and '9', the corresponding value between 0 and
- /// 9. If `c` is 'a' or 'A', 10. If `c` is 'b' or 'B', 11, etc. Returns
- /// none if the character does not refer to a digit in the given radix.
+ /// Returns `None` if the `char` does not refer to a digit in the given radix.
///
/// # Panics
///
- /// Panics if given a radix outside the range [0..36].
+ /// Panics if given a radix larger than 36.
///
/// # Examples
///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let d = '1';
+ ///
+ /// assert_eq!(d.to_digit(10), Some(1));
+ ///
+ /// let d = 'f';
+ ///
+ /// assert_eq!(d.to_digit(16), Some(15));
+ /// ```
+ ///
+ /// Passing a non-digit results in failure:
+ ///
+ /// ```
+ /// let d = 'f';
+ ///
+ /// assert_eq!(d.to_digit(10), None);
+ ///
+ /// let d = 'z';
+ ///
+ /// assert_eq!(d.to_digit(16), None);
+ /// ```
+ ///
+ /// Passing a large radix, causing a panic:
+ ///
/// ```
- /// let c = '1';
+ /// use std::thread;
///
- /// assert_eq!(c.to_digit(10), Some(1));
+ /// let result = thread::spawn(|| {
+ /// let d = '1';
///
- /// assert_eq!('f'.to_digit(16), Some(15));
+ /// d.to_digit(37);
+ /// }).join();
+ ///
+ /// assert!(result.is_err());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn to_digit(self, radix: u32) -> Option<u32> { C::to_digit(self, radix) }
+ pub fn to_digit(self, radix: u32) -> Option<u32> {
+ C::to_digit(self, radix)
+ }
/// Returns an iterator that yields the hexadecimal Unicode escape of a
/// character, as `char`s.
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn escape_unicode(self) -> EscapeUnicode { C::escape_unicode(self) }
+ pub fn escape_unicode(self) -> EscapeUnicode {
+ C::escape_unicode(self)
+ }
- /// Returns an iterator that yields the 'default' ASCII and
- /// C++11-like literal escape of a character, as `char`s.
+ /// Returns an iterator that yields the literal escape code of a `char`.
///
/// The default is chosen with a bias toward producing literals that are
/// legal in a variety of languages, including C++11 and similar C-family
/// languages. The exact rules are:
///
- /// * Tab, CR and LF are escaped as '\t', '\r' and '\n' respectively.
- /// * Single-quote, double-quote and backslash chars are backslash-
- /// escaped.
- /// * Any other chars in the range [0x20,0x7e] are not escaped.
- /// * Any other chars are given hex Unicode escapes; see `escape_unicode`.
+ /// * Tab is escaped as `\t`.
+ /// * Carriage return is escaped as `\r`.
+ /// * Line feed is escaped as `\n`.
+ /// * Single quote is escaped as `\'`.
+ /// * Double quote is escaped as `\"`.
+ /// * Backslash is escaped as `\\`.
+ /// * Any character in the 'printable ASCII' range `0x20` .. `0x7e`
+ /// inclusive is not escaped.
+ /// * All other characters are given hexadecimal Unicode escapes; see
+ /// [`escape_unicode`][escape_unicode].
+ ///
+ /// [escape_unicode]: #method.escape_unicode
///
/// # Examples
///
+ /// Basic usage:
+ ///
/// ```
/// for i in '"'.escape_default() {
/// println!("{}", i);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn escape_default(self) -> EscapeDefault { C::escape_default(self) }
+ pub fn escape_default(self) -> EscapeDefault {
+ C::escape_default(self)
+ }
- /// Returns the number of bytes this character would need if encoded in
- /// UTF-8.
+ /// Returns the number of bytes this `char` would need if encoded in UTF-8.
+ ///
+ /// That number of bytes is always between 1 and 4, inclusive.
///
/// # Examples
///
+ /// Basic usage:
+ ///
/// ```
- /// let n = 'ß'.len_utf8();
+ /// let len = 'A'.len_utf8();
+ /// assert_eq!(len, 1);
+ ///
+ /// let len = 'ß'.len_utf8();
+ /// assert_eq!(len, 2);
+ ///
+ /// let len = 'ℝ'.len_utf8();
+ /// assert_eq!(len, 3);
///
- /// assert_eq!(n, 2);
+ /// let len = '💣'.len_utf8();
+ /// assert_eq!(len, 4);
+ /// ```
+ ///
+ /// The `&str` type guarantees that its contents are UTF-8, and so we can compare the length it
+ /// would take if each code point was represented as a `char` vs in the `&str` itself:
+ ///
+ /// ```
+ /// // as chars
+ /// let eastern = '東';
+ /// let capitol = '京';
+ ///
+ /// // both can be represented as three bytes
+ /// assert_eq!(3, eastern.len_utf8());
+ /// assert_eq!(3, capitol.len_utf8());
+ ///
+ /// // as a &str, these two are encoded in UTF-8
+ /// let tokyo = "東京";
+ ///
+ /// let len = eastern.len_utf8() + capitol.len_utf8();
+ ///
+ /// // we can see that they take six bytes total...
+ /// assert_eq!(6, tokyo.len());
+ ///
+ /// // ... just like the &str
+ /// assert_eq!(len, tokyo.len());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn len_utf8(self) -> usize { C::len_utf8(self) }
+ pub fn len_utf8(self) -> usize {
+ C::len_utf8(self)
+ }
- /// Returns the number of 16-bit code units this character would need if
+ /// Returns the number of 16-bit code units this `char` would need if
/// encoded in UTF-16.
///
+ /// See the documentation for [`len_utf8()`][len_utf8] for more explanation
+ /// of this concept. This function is a mirror, but for UTF-16 instead of
+ /// UTF-8.
+ ///
/// # Examples
///
/// ```
/// let n = 'ß'.len_utf16();
- ///
/// assert_eq!(n, 1);
+ ///
+ /// let len = '💣'.len_utf16();
+ /// assert_eq!(len, 2);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn len_utf16(self) -> usize { C::len_utf16(self) }
+ pub fn len_utf16(self) -> usize {
+ C::len_utf16(self)
+ }
/// Encodes this character as UTF-8 into the provided byte buffer, and then
/// returns the number of bytes written.
C::encode_utf16(self, dst)
}
- /// Returns whether the specified character is considered a Unicode
- /// alphabetic code point.
+ /// Returns true if this `char` is an alphabetic code point, and false if not.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let c = 'a';
+ ///
+ /// assert!(c.is_alphabetic());
+ ///
+ /// let c = '京';
+ /// assert!(c.is_alphabetic());
+ ///
+ /// let c = '💝';
+ /// // love is many things, but it is not alphabetic
+ /// assert!(!c.is_alphabetic());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_alphabetic(self) -> bool {
match self {
- 'a' ... 'z' | 'A' ... 'Z' => true,
+ 'a'...'z' | 'A'...'Z' => true,
c if c > '\x7f' => derived_property::Alphabetic(c),
- _ => false
+ _ => false,
}
}
- /// Returns whether the specified character satisfies the 'XID_Start'
- /// Unicode property.
+ /// Returns true if this `char` satisfies the 'XID_Start' Unicode property, and false
+ /// otherwise.
///
/// 'XID_Start' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
- /// mostly similar to ID_Start but modified for closure under NFKx.
+ /// mostly similar to `ID_Start` but modified for closure under `NFKx`.
#[unstable(feature = "unicode",
reason = "mainly needed for compiler internals",
issue = "0")]
#[inline]
- pub fn is_xid_start(self) -> bool { derived_property::XID_Start(self) }
+ pub fn is_xid_start(self) -> bool {
+ derived_property::XID_Start(self)
+ }
- /// Returns whether the specified `char` satisfies the 'XID_Continue'
- /// Unicode property.
+ /// Returns true if this `char` satisfies the 'XID_Continue' Unicode property, and false
+ /// otherwise.
///
/// 'XID_Continue' is a Unicode Derived Property specified in
/// [UAX #31](http://unicode.org/reports/tr31/#NFKC_Modifications),
reason = "mainly needed for compiler internals",
issue = "0")]
#[inline]
- pub fn is_xid_continue(self) -> bool { derived_property::XID_Continue(self) }
+ pub fn is_xid_continue(self) -> bool {
+ derived_property::XID_Continue(self)
+ }
- /// Indicates whether a character is in lowercase.
+ /// Returns true if this `char` is lowercase, and false otherwise.
///
- /// This is defined according to the terms of the Unicode Derived Core
+ /// 'Lowercase' is defined according to the terms of the Unicode Derived Core
/// Property `Lowercase`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let c = 'a';
+ /// assert!(c.is_lowercase());
+ ///
+ /// let c = 'δ';
+ /// assert!(c.is_lowercase());
+ ///
+ /// let c = 'A';
+ /// assert!(!c.is_lowercase());
+ ///
+ /// let c = 'Δ';
+ /// assert!(!c.is_lowercase());
+ ///
+ /// // The various Chinese scripts do not have case, and so:
+ /// let c = '中';
+ /// assert!(!c.is_lowercase());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_lowercase(self) -> bool {
match self {
- 'a' ... 'z' => true,
+ 'a'...'z' => true,
c if c > '\x7f' => derived_property::Lowercase(c),
- _ => false
+ _ => false,
}
}
- /// Indicates whether a character is in uppercase.
+ /// Returns true if this `char` is uppercase, and false otherwise.
///
- /// This is defined according to the terms of the Unicode Derived Core
+ /// 'Uppercase' is defined according to the terms of the Unicode Derived Core
/// Property `Uppercase`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let c = 'a';
+ /// assert!(!c.is_uppercase());
+ ///
+ /// let c = 'δ';
+ /// assert!(!c.is_uppercase());
+ ///
+ /// let c = 'A';
+ /// assert!(c.is_uppercase());
+ ///
+ /// let c = 'Δ';
+ /// assert!(c.is_uppercase());
+ ///
+ /// // The various Chinese scripts do not have case, and so:
+ /// let c = '中';
+ /// assert!(!c.is_uppercase());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_uppercase(self) -> bool {
match self {
- 'A' ... 'Z' => true,
+ 'A'...'Z' => true,
c if c > '\x7f' => derived_property::Uppercase(c),
- _ => false
+ _ => false,
}
}
- /// Indicates whether a character is whitespace.
+ /// Returns true if this `char` is whitespace, and false otherwise.
+ ///
+ /// 'Whitespace' is defined according to the terms of the Unicode Derived Core
+ /// Property `White_Space`.
+ ///
+ /// # Examples
///
- /// Whitespace is defined in terms of the Unicode Property `White_Space`.
+ /// Basic usage:
+ ///
+ /// ```
+ /// let c = ' ';
+ /// assert!(c.is_whitespace());
+ ///
+ /// // a non-breaking space
+ /// let c = '\u{A0}';
+ /// assert!(c.is_whitespace());
+ ///
+ /// let c = '越';
+ /// assert!(!c.is_whitespace());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_whitespace(self) -> bool {
match self {
- ' ' | '\x09' ... '\x0d' => true,
+ ' ' | '\x09'...'\x0d' => true,
c if c > '\x7f' => property::White_Space(c),
- _ => false
+ _ => false,
}
}
- /// Indicates whether a character is alphanumeric.
+ /// Returns true if this `char` is alphanumeric, and false otherwise.
///
- /// Alphanumericness is defined in terms of the Unicode General Categories
+ /// 'Alphanumeric'-ness is defined in terms of the Unicode General Categories
/// 'Nd', 'Nl', 'No' and the Derived Core Property 'Alphabetic'.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let c = '٣';
+ /// assert!(c.is_alphanumeric());
+ ///
+ /// let c = '7';
+ /// assert!(c.is_alphanumeric());
+ ///
+ /// let c = '৬';
+ /// assert!(c.is_alphanumeric());
+ ///
+ /// let c = 'K';
+ /// assert!(c.is_alphanumeric());
+ ///
+ /// let c = 'و';
+ /// assert!(c.is_alphanumeric());
+ ///
+ /// let c = '藏';
+ /// assert!(c.is_alphanumeric());
+ ///
+ /// let c = '¾';
+ /// assert!(!c.is_alphanumeric());
+ ///
+ /// let c = '①';
+ /// assert!(!c.is_alphanumeric());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_alphanumeric(self) -> bool {
self.is_alphabetic() || self.is_numeric()
}
- /// Indicates whether a character is a control code point.
+ /// Returns true if this `char` is a control code point, and false otherwise.
///
- /// Control code points are defined in terms of the Unicode General
+ /// 'Control code point' is defined in terms of the Unicode General
/// Category `Cc`.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// // U+009C, STRING TERMINATOR
+ /// let c = '\9c';
+ /// assert!(c.is_control());
+ ///
+ /// let c = 'q';
+ /// assert!(!c.is_control());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
- pub fn is_control(self) -> bool { general_category::Cc(self) }
+ pub fn is_control(self) -> bool {
+ general_category::Cc(self)
+ }
- /// Indicates whether the character is numeric (Nd, Nl, or No).
+ /// Returns true if this `char` is numeric, and false otherwise.
+ ///
+ /// 'Numeric'-ness is defined in terms of the Unicode General Categories
+ /// 'Nd', 'Nl', 'No'.
+ ///
+ /// # Examples
+ ///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let c = '٣';
+ /// assert!(c.is_numeric());
+ ///
+ /// let c = '7';
+ /// assert!(c.is_numeric());
+ ///
+ /// let c = '৬';
+ /// assert!(c.is_numeric());
+ ///
+ /// let c = 'K';
+ /// assert!(!c.is_numeric());
+ ///
+ /// let c = 'و';
+ /// assert!(!c.is_numeric());
+ ///
+ /// let c = '藏';
+ /// assert!(!c.is_numeric());
+ ///
+ /// let c = '¾';
+ /// assert!(!c.is_numeric());
+ ///
+ /// let c = '①';
+ /// assert!(!c.is_numeric());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn is_numeric(self) -> bool {
match self {
- '0' ... '9' => true,
+ '0'...'9' => true,
c if c > '\x7f' => general_category::N(c),
- _ => false
+ _ => false,
}
}
- /// Converts a character to its lowercase equivalent.
+ /// Returns an iterator that yields the lowercase equivalent of a `char`.
///
- /// This performs complex unconditional mappings with no tailoring.
- /// See `to_uppercase()` for references and more information.
+ /// If no conversion is possible then an iterator with just the input character is returned.
///
- /// # Return value
+ /// This performs complex unconditional mappings with no tailoring: it maps
+ /// one Unicode character to its lowercase equivalent according to the
+ /// [Unicode database] and the additional complex mappings
+ /// [`SpecialCasing.txt`]. Conditional mappings (based on context or
+ /// language) are not considered here.
///
- /// Returns an iterator which yields the characters corresponding to the
- /// lowercase equivalent of the character. If no conversion is possible then
- /// an iterator with just the input character is returned.
+ /// For a full reference, see [here][reference].
+ ///
+ /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
+ ///
+ /// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt
+ ///
+ /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
///
/// # Examples
///
+ /// Basic usage:
+ ///
/// ```
- /// assert_eq!(Some('c'), 'C'.to_lowercase().next());
+ /// let c = 'c';
+ ///
+ /// assert_eq!(c.to_uppercase().next(), Some('C'));
+ ///
+ /// // Japanese scripts do not have case, and so:
+ /// let c = '山';
+ /// assert_eq!(c.to_uppercase().next(), Some('山'));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
ToLowercase(CaseMappingIter::new(conversions::to_lower(self)))
}
- /// Converts a character to its uppercase equivalent.
- ///
- /// This performs complex unconditional mappings with no tailoring:
- /// it maps one Unicode character to its uppercase equivalent
- /// according to the Unicode database [1]
- /// and the additional complex mappings [`SpecialCasing.txt`].
- /// Conditional mappings (based on context or language) are not considered here.
+ /// Returns an iterator that yields the uppercase equivalent of a `char`.
///
- /// A full reference can be found here [2].
+ /// If no conversion is possible then an iterator with just the input character is returned.
///
- /// # Return value
+ /// This performs complex unconditional mappings with no tailoring: it maps
+ /// one Unicode character to its uppercase equivalent according to the
+ /// [Unicode database] and the additional complex mappings
+ /// [`SpecialCasing.txt`]. Conditional mappings (based on context or
+ /// language) are not considered here.
///
- /// Returns an iterator which yields the characters corresponding to the
- /// uppercase equivalent of the character. If no conversion is possible then
- /// an iterator with just the input character is returned.
+ /// For a full reference, see [here][reference].
///
- /// [1]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
+ /// [Unicode database]: ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt
///
/// [`SpecialCasing.txt`]: ftp://ftp.unicode.org/Public/UNIDATA/SpecialCasing.txt
///
- /// [2]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
+ /// [reference]: http://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
///
/// # Examples
///
+ /// Basic usage:
+ ///
+ /// ```
+ /// let c = 'c';
+ /// assert_eq!(c.to_uppercase().next(), Some('C'));
+ ///
+ /// // Japanese does not have case, and so:
+ /// let c = '山';
+ /// assert_eq!(c.to_uppercase().next(), Some('山'));
+ /// ```
+ ///
+ /// In Turkish, the equivalent of 'i' in Latin has five forms instead of two:
+ ///
+ /// * 'Dotless': I / ı, sometimes written ï
+ /// * 'Dotted': İ / i
+ ///
+ /// Note that the lowercase dotted 'i' is the same as the Latin. Therefore:
+ ///
+ /// ```
+ /// let i = 'i';
+ ///
+ /// let upper_i = i.to_uppercase().next();
+ /// ```
+ ///
+ /// The value of `upper_i` here relies on the language of the text: if we're
+ /// in `en-US`, it should be `Some('I')`, but if we're in `tr_TR`, it should
+ /// be `Some('İ')`. `to_uppercase()` does not take this into account, and so:
+ ///
/// ```
- /// assert_eq!(Some('C'), 'c'.to_uppercase().next());
+ /// let i = 'i';
+ ///
+ /// let upper_i = i.to_uppercase().next();
+ ///
+ /// assert_eq!(Some('I'), upper_i);
/// ```
+ ///
+ /// holds across languages.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn to_uppercase(self) -> ToUppercase {
}
}
-/// An iterator that decodes UTF-16 encoded codepoints from an iterator of `u16`s.
+/// An iterator that decodes UTF-16 encoded code points from an iterator of `u16`s.
#[unstable(feature = "decode_utf16", reason = "recently exposed", issue = "27830")]
#[derive(Clone)]
-pub struct DecodeUtf16<I> where I: Iterator<Item=u16> {
+pub struct DecodeUtf16<I>
+ where I: Iterator<Item = u16>
+{
iter: I,
buf: Option<u16>,
}
-/// Create an iterator over the UTF-16 encoded codepoints in `iterable`,
+/// Create an iterator over the UTF-16 encoded code points in `iterable`,
/// returning unpaired surrogates as `Err`s.
///
/// # Examples
/// ```
#[unstable(feature = "decode_utf16", reason = "recently exposed", issue = "27830")]
#[inline]
-pub fn decode_utf16<I: IntoIterator<Item=u16>>(iterable: I) -> DecodeUtf16<I::IntoIter> {
+pub fn decode_utf16<I: IntoIterator<Item = u16>>(iterable: I) -> DecodeUtf16<I::IntoIter> {
DecodeUtf16 {
iter: iterable.into_iter(),
buf: None,
Some(buf) => buf,
None => match self.iter.next() {
Some(u) => u,
- None => return None
- }
+ None => return None,
+ },
};
if u < 0xD800 || 0xDFFF < u {
let u2 = match self.iter.next() {
Some(u2) => u2,
// eof
- None => return Some(Err(u))
+ None => return Some(Err(u)),
};
if u2 < 0xDC00 || u2 > 0xDFFF {
// not a trailing surrogate so we're not a valid
// surrogate pair, so rewind to redecode u2 next time.
self.buf = Some(u2);
- return Some(Err(u))
+ return Some(Err(u));
}
// all ok, so lets decode it.
}
}
-/// U+FFFD REPLACEMENT CHARACTER (�) is used in Unicode to represent a decoding error.
-/// It can occur, for example, when giving ill-formed UTF-8 bytes to `String::from_utf8_lossy`.
+/// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a decoding error.
+/// It can occur, for example, when giving ill-formed UTF-8 bytes to
+/// [`String::from_utf8_lossy`](../string/struct.String.html#method.from_utf8_lossy).
#[unstable(feature = "decode_utf16", reason = "recently added", issue = "27830")]
pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}';
test(no_crate_inject))]
#![no_std]
-#![feature(char_from_unchecked)]
#![feature(core_char_ext)]
#![feature(core_slice_ext)]
#![feature(core_str_ext)]
//! Unicode-intensive string manipulations.
//!
-//! This module provides functionality to `str` that requires the Unicode methods provided by the
-//! unicode parts of the CharExt trait.
+//! This module provides functionality to `str` that requires the Unicode
+//! methods provided by the unicode parts of the CharExt trait.
use char::{DecodeUtf16, decode_utf16};
use core::char;
impl UnicodeStr for str {
#[inline]
fn split_whitespace(&self) -> SplitWhitespace {
- fn is_not_empty(s: &&str) -> bool { !s.is_empty() }
+ fn is_not_empty(s: &&str) -> bool {
+ !s.is_empty()
+ }
let is_not_empty: fn(&&str) -> bool = is_not_empty; // coerce to fn pointer
- fn is_whitespace(c: char) -> bool { c.is_whitespace() }
+ fn is_whitespace(c: char) -> bool {
+ c.is_whitespace()
+ }
let is_whitespace: fn(char) -> bool = is_whitespace; // coerce to fn pointer
SplitWhitespace { inner: self.split(is_whitespace).filter(is_not_empty) }
}
#[inline]
- fn is_whitespace(&self) -> bool { self.chars().all(|c| c.is_whitespace()) }
+ fn is_whitespace(&self) -> bool {
+ self.chars().all(|c| c.is_whitespace())
+ }
#[inline]
- fn is_alphanumeric(&self) -> bool { self.chars().all(|c| c.is_alphanumeric()) }
+ fn is_alphanumeric(&self) -> bool {
+ self.chars().all(|c| c.is_alphanumeric())
+ }
#[inline]
fn trim(&self) -> &str {
Some(_) => {}
None => {
let u2 = next!(false);
- if u < 0xD7FF || u > 0xDBFF ||
- u2 < 0xDC00 || u2 > 0xDFFF { return false; }
+ if u < 0xD7FF || u > 0xDBFF || u2 < 0xDC00 || u2 > 0xDFFF {
+ return false;
+ }
}
}
}
#[allow(deprecated)]
#[derive(Clone)]
pub struct Utf16Items<'a> {
- decoder: DecodeUtf16<Cloned<slice::Iter<'a, u16>>>
+ decoder: DecodeUtf16<Cloned<slice::Iter<'a, u16>>>,
}
/// The possibilities for values decoded from a `u16` stream.
/// A valid codepoint.
ScalarValue(char),
/// An invalid surrogate without its pair.
- LoneSurrogate(u16)
+ LoneSurrogate(u16),
}
#[allow(deprecated)]
pub fn to_char_lossy(&self) -> char {
match *self {
Utf16Item::ScalarValue(c) => c,
- Utf16Item::LoneSurrogate(_) => '\u{FFFD}'
+ Utf16Item::LoneSurrogate(_) => '\u{FFFD}',
}
}
}
type Item = Utf16Item;
fn next(&mut self) -> Option<Utf16Item> {
- self.decoder.next().map(|result| match result {
- Ok(c) => Utf16Item::ScalarValue(c),
- Err(s) => Utf16Item::LoneSurrogate(s),
+ self.decoder.next().map(|result| {
+ match result {
+ Ok(c) => Utf16Item::ScalarValue(c),
+ Err(s) => Utf16Item::LoneSurrogate(s),
+ }
})
}
#[derive(Clone)]
pub struct Utf16Encoder<I> {
chars: I,
- extra: u16
+ extra: u16,
}
impl<I> Utf16Encoder<I> {
/// Create a UTF-16 encoder from any `char` iterator.
- pub fn new(chars: I) -> Utf16Encoder<I> where I: Iterator<Item=char> {
- Utf16Encoder { chars: chars, extra: 0 }
+ pub fn new(chars: I) -> Utf16Encoder<I>
+ where I: Iterator<Item = char>
+ {
+ Utf16Encoder {
+ chars: chars,
+ extra: 0,
+ }
}
}
let mut buf = [0; 2];
self.chars.next().map(|ch| {
let n = CharExt::encode_utf16(ch, &mut buf).unwrap_or(0);
- if n == 2 { self.extra = buf[1]; }
+ if n == 2 {
+ self.extra = buf[1];
+ }
buf[0]
})
}
impl<'a> Iterator for SplitWhitespace<'a> {
type Item = &'a str;
- fn next(&mut self) -> Option<&'a str> { self.inner.next() }
+ fn next(&mut self) -> Option<&'a str> {
+ self.inner.next()
+ }
}
impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
- fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() }
+ fn next_back(&mut self) -> Option<&'a str> {
+ self.inner.next_back()
+ }
}
use std::collections::HashSet;
use syntax::ast;
-use rustc_front::attr::AttrMetaMethods;
+use syntax::attr::AttrMetaMethods;
use rustc_front::hir;
use rustc::metadata::csearch;
///
/// The returned value is `None` if the `id` could not be inlined, and `Some`
/// of a vector of items if it was successfully expanded.
-pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option<ast::Ident>)
+pub fn try_inline(cx: &DocContext, id: ast::NodeId, into: Option<ast::Name>)
-> Option<Vec<clean::Item>> {
let tcx = match cx.tcx_opt() {
Some(tcx) => tcx,
ty::ConstTraitItem(ref assoc_const) => {
let did = assoc_const.def_id;
let type_scheme = tcx.lookup_item_type(did);
- let default = match assoc_const.default {
- Some(_) => Some(const_eval::lookup_const_by_id(tcx, did, None)
- .unwrap().span.to_src(cx)),
- None => None,
+ let default = if assoc_const.has_value {
+ Some(const_eval::lookup_const_by_id(tcx, did, None)
+ .unwrap().span.to_src(cx))
+ } else {
+ None
};
Some(clean::Item {
name: Some(assoc_const.name.clean(cx)),
if method.vis != hir::Public && associated_trait.is_none() {
return None
}
- if method.provided_source.is_some() {
- return None
- }
let mut item = method.clean(cx);
item.inner = match item.inner.clone() {
clean::TyMethodItem(clean::TyMethod {
use syntax;
use syntax::abi;
use syntax::ast;
+use syntax::attr;
+use syntax::attr::{AttributeMethods, AttrMetaMethods};
use syntax::codemap;
use syntax::codemap::{DUMMY_SP, Pos, Spanned};
use syntax::parse::token::{self, InternedString, special_idents};
use rustc::metadata::csearch;
use rustc::metadata::decoder;
use rustc::middle::def;
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
+use rustc::middle::def_id::{DefId, DefIndex};
use rustc::middle::subst::{self, ParamSpace, VecPerParamSpace};
use rustc::middle::ty;
use rustc::middle::stability;
use rustc_front::hir;
-use rustc_front::attr;
-use rustc_front::attr::{AttributeMethods, AttrMetaMethods};
-use rustc_front::lowering::unlower_attribute;
use std::collections::HashMap;
use std::path::PathBuf;
// Figure out the name of this crate
let input = &cx.input;
- let attrs: Vec<_> = self.attrs.iter().map(|a| unlower_attribute(a)).collect();
- let name = link::find_crate_name(None, &attrs, input);
+ let name = link::find_crate_name(None, &self.attrs, input);
// Clean the crate, translating the entire libsyntax AST to one that is
// understood by rustdoc.
//
// Note that this loop only searches the top-level items of the crate,
// and this is intentional. If we were to search the entire crate for an
- // item tagged with `#[doc(primitive)]` then we we would also have to
+ // item tagged with `#[doc(primitive)]` then we would also have to
// search the entirety of external modules for items tagged
// `#[doc(primitive)]`, which is a pretty inefficient process (decoding
// all that metadata unconditionally).
attrs: child.attrs.clone(),
visibility: Some(hir::Public),
stability: None,
- def_id: DefId::local(prim.to_node_id()),
+ def_id: DefId::local(prim.to_def_index()),
inner: PrimitiveItem(prim),
});
}
match self.stability {
Some(ref s) => {
let mut base = match s.level {
- attr::Unstable => "unstable".to_string(),
- attr::Stable => String::new(),
+ stability::Unstable => "unstable".to_string(),
+ stability::Stable => String::new(),
};
if !s.deprecated_since.is_empty() {
base.push_str(" deprecated");
source: whence.clean(cx),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
inner: ModuleItem(Module {
is_crate: self.is_crate,
items: items
NameValue(String, String)
}
-impl Clean<Attribute> for hir::MetaItem {
+impl Clean<Attribute> for ast::MetaItem {
fn clean(&self, cx: &DocContext) -> Attribute {
match self.node {
- hir::MetaWord(ref s) => Word(s.to_string()),
- hir::MetaList(ref s, ref l) => {
+ ast::MetaWord(ref s) => Word(s.to_string()),
+ ast::MetaList(ref s, ref l) => {
List(s.to_string(), l.clean(cx))
}
- hir::MetaNameValue(ref s, ref v) => {
+ ast::MetaNameValue(ref s, ref v) => {
NameValue(s.to_string(), lit_to_string(v))
}
}
}
}
-impl Clean<Attribute> for hir::Attribute {
+impl Clean<Attribute> for ast::Attribute {
fn clean(&self, cx: &DocContext) -> Attribute {
self.with_desugared_doc(|a| a.node.value.clean(cx))
}
_ => None,
}
}
- fn meta_item_list<'a>(&'a self) -> Option<&'a [P<hir::MetaItem>]> { None }
+ fn meta_item_list<'a>(&'a self) -> Option<&'a [P<ast::MetaItem>]> { None }
fn span(&self) -> codemap::Span { unimplemented!() }
}
impl<'a> attr::AttrMetaMethods for &'a Attribute {
fn name(&self) -> InternedString { (**self).name() }
fn value_str(&self) -> Option<InternedString> { (**self).value_str() }
- fn meta_item_list(&self) -> Option<&[P<hir::MetaItem>]> { None }
+ fn meta_item_list(&self) -> Option<&[P<ast::MetaItem>]> { None }
fn span(&self) -> codemap::Span { unimplemented!() }
}
impl Clean<TyParam> for hir::TyParam {
fn clean(&self, cx: &DocContext) -> TyParam {
TyParam {
- name: self.ident.clean(cx),
- did: DefId { krate: LOCAL_CRATE, node: self.id },
+ name: self.name.clean(cx),
+ did: cx.map.local_def_id(self.id),
bounds: self.bounds.clean(cx),
default: self.default.clean(cx),
}
source: self.whence.clean(cx),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
inner: FunctionItem(Function {
decl: self.decl.clean(cx),
generics: self.generics.clean(cx),
impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
fn clean(&self, cx: &DocContext) -> FnDecl {
let (did, sig) = *self;
- let mut names = if did.node != 0 {
- csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
+ let mut names = if let Some(_) = cx.map.as_local_node_id(did) {
+ vec![].into_iter()
} else {
- Vec::new().into_iter()
+ csearch::get_method_arg_names(&cx.tcx().sess.cstore, did).into_iter()
}.peekable();
if names.peek().map(|s| &**s) == Some("self") {
let _ = names.next();
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: TraitItem(Trait {
}
};
Item {
- name: Some(self.ident.clean(cx)),
+ name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.span.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: None,
- stability: get_stability(cx, DefId::local(self.id)),
+ stability: get_stability(cx, cx.map.local_def_id(self.id)),
inner: inner
}
}
}, true),
};
Item {
- name: Some(self.ident.clean(cx)),
+ name: Some(self.name.clean(cx)),
source: self.span.clean(cx),
attrs: self.attrs.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
- stability: get_stability(cx, DefId::local(self.id)),
+ stability: get_stability(cx, cx.map.local_def_id(self.id)),
inner: inner
}
}
/// Creates a rustdoc-specific node id for primitive types.
///
/// These node ids are generally never used by the AST itself.
- pub fn to_node_id(&self) -> ast::NodeId {
- u32::MAX - 1 - (*self as u32)
+ pub fn to_def_index(&self) -> DefIndex {
+ let x = u32::MAX - 1 - (*self as u32);
+ DefIndex::new(x as usize)
}
}
let mut trait_path = p.clone();
trait_path.segments.pop();
Type::QPath {
- name: p.segments.last().unwrap().identifier.clean(cx),
+ name: p.segments.last().unwrap().identifier.name.clean(cx),
self_type: box qself.ty.clean(cx),
trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
}
match self.sty {
ty::TyBool => Primitive(Bool),
ty::TyChar => Primitive(Char),
- ty::TyInt(hir::TyIs) => Primitive(Isize),
- ty::TyInt(hir::TyI8) => Primitive(I8),
- ty::TyInt(hir::TyI16) => Primitive(I16),
- ty::TyInt(hir::TyI32) => Primitive(I32),
- ty::TyInt(hir::TyI64) => Primitive(I64),
- ty::TyUint(hir::TyUs) => Primitive(Usize),
- ty::TyUint(hir::TyU8) => Primitive(U8),
- ty::TyUint(hir::TyU16) => Primitive(U16),
- ty::TyUint(hir::TyU32) => Primitive(U32),
- ty::TyUint(hir::TyU64) => Primitive(U64),
- ty::TyFloat(hir::TyF32) => Primitive(F32),
- ty::TyFloat(hir::TyF64) => Primitive(F64),
+ ty::TyInt(ast::TyIs) => Primitive(Isize),
+ ty::TyInt(ast::TyI8) => Primitive(I8),
+ ty::TyInt(ast::TyI16) => Primitive(I16),
+ ty::TyInt(ast::TyI32) => Primitive(I32),
+ ty::TyInt(ast::TyI64) => Primitive(I64),
+ ty::TyUint(ast::TyUs) => Primitive(Usize),
+ ty::TyUint(ast::TyU8) => Primitive(U8),
+ ty::TyUint(ast::TyU16) => Primitive(U16),
+ ty::TyUint(ast::TyU32) => Primitive(U32),
+ ty::TyUint(ast::TyU64) => Primitive(U64),
+ ty::TyFloat(ast::TyF32) => Primitive(F32),
+ ty::TyFloat(ast::TyF64) => Primitive(F64),
ty::TyStr => Primitive(Str),
ty::TyBox(t) => {
let box_did = cx.tcx_opt().and_then(|tcx| {
type_params: Vec::new(),
where_predicates: Vec::new()
},
- decl: (DefId::local(0), &fty.sig).clean(cx),
+ decl: (cx.map.local_def_id(0), &fty.sig).clean(cx),
abi: fty.abi.to_string(),
}),
ty::TyStruct(def, substs) |
attrs: self.node.attrs.clean(cx),
source: self.span.clean(cx),
visibility: Some(vis),
- stability: get_stability(cx, DefId::local(self.node.id)),
- def_id: DefId::local(self.node.id),
+ stability: get_stability(cx, cx.map.local_def_id(self.node.id)),
+ def_id: cx.map.local_def_id(self.node.id),
inner: StructFieldItem(TypedStructField(self.node.ty.clean(cx))),
}
}
let (name, attrs) = if self.name == unnamed_field.name {
(None, None)
} else {
- (Some(self.name), Some(attr_map.get(&self.did.node).unwrap()))
+ (Some(self.name), Some(attr_map.get(&self.did).unwrap()))
};
Item {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: StructItem(Struct {
pub fields_stripped: bool,
}
-impl Clean<VariantStruct> for ::rustc_front::hir::StructDef {
+impl Clean<VariantStruct> for ::rustc_front::hir::VariantData {
fn clean(&self, cx: &DocContext) -> VariantStruct {
VariantStruct {
struct_type: doctree::struct_type_from_def(self),
- fields: self.fields.clean(cx),
+ fields: self.fields().iter().map(|x| x.clean(cx)).collect(),
fields_stripped: false,
}
}
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: EnumItem(Enum {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- visibility: self.vis.clean(cx),
+ visibility: None,
stability: self.stab.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.def.id()),
inner: VariantItem(Variant {
- kind: self.kind.clean(cx),
+ kind: struct_def_to_variant_kind(&self.def, cx),
}),
}
}
self.fields.iter().map(|f| f.unsubst_ty().clean(cx)).collect()
)
}
- ty::VariantKind::Dict => {
+ ty::VariantKind::Struct => {
StructVariant(VariantStruct {
struct_type: doctree::Plain,
fields_stripped: false,
StructVariant(VariantStruct),
}
-impl Clean<VariantKind> for hir::VariantKind {
- fn clean(&self, cx: &DocContext) -> VariantKind {
- match self {
- &hir::TupleVariantKind(ref args) => {
- if args.is_empty() {
- CLikeVariant
- } else {
- TupleVariant(args.iter().map(|x| x.ty.clean(cx)).collect())
- }
- },
- &hir::StructVariantKind(ref sd) => StructVariant(sd.clean(cx)),
- }
+fn struct_def_to_variant_kind(struct_def: &hir::VariantData, cx: &DocContext) -> VariantKind {
+ if struct_def.is_struct() {
+ StructVariant(struct_def.clean(cx))
+ } else if struct_def.is_unit() {
+ CLikeVariant
+ } else {
+ TupleVariant(struct_def.fields().iter().map(|x| x.node.ty.clean(cx)).collect())
}
}
impl Clean<PathSegment> for hir::PathSegment {
fn clean(&self, cx: &DocContext) -> PathSegment {
PathSegment {
- name: self.identifier.clean(cx),
+ name: self.identifier.name.clean(cx),
params: self.parameters.clean(cx)
}
}
s
}
-impl Clean<String> for ast::Ident {
- fn clean(&self, _: &DocContext) -> String {
- self.to_string()
- }
-}
-
impl Clean<String> for ast::Name {
fn clean(&self, _: &DocContext) -> String {
self.to_string()
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id.clone()),
+ def_id: cx.map.local_def_id(self.id.clone()),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: TypedefItem(Typedef {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: StaticItem(Static {
name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: ConstantItem(Constant {
name: None,
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
stability: self.stab.clean(cx),
inner: ImplItem(Impl {
name: None,
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: Some(hir::Public),
stability: None,
inner: DefaultImplItem(DefaultImpl {
name: None,
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(0),
+ def_id: cx.map.local_def_id(0),
visibility: self.vis.clean(cx),
stability: None,
inner: ExternCrateItem(self.name.clean(cx), self.path.clone())
(ret, ImportList(resolve_use_source(cx, p.clean(cx), self.id),
remaining))
}
- hir::ViewPathSimple(i, ref p) => {
+ hir::ViewPathSimple(name, ref p) => {
if !denied {
- match inline::try_inline(cx, self.id, Some(i)) {
+ match inline::try_inline(cx, self.id, Some(name)) {
Some(items) => return items,
None => {}
}
}
- (vec![], SimpleImport(i.clean(cx),
+ (vec![], SimpleImport(name.clean(cx),
resolve_use_source(cx, p.clean(cx), self.id)))
}
};
name: None,
attrs: self.attrs.clean(cx),
source: self.whence.clean(cx),
- def_id: DefId::local(0),
+ def_id: cx.map.local_def_id(0),
visibility: self.vis.clean(cx),
stability: None,
inner: ImportItem(inner)
}
};
Item {
- name: Some(self.ident.clean(cx)),
+ name: Some(self.name.clean(cx)),
attrs: self.attrs.clean(cx),
source: self.span.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
visibility: self.vis.clean(cx),
- stability: get_stability(cx, DefId::local(self.id)),
+ stability: get_stability(cx, cx.map.local_def_id(self.id)),
inner: inner,
}
}
}
}
-fn lit_to_string(lit: &hir::Lit) -> String {
+fn lit_to_string(lit: &ast::Lit) -> String {
match lit.node {
- hir::LitStr(ref st, _) => st.to_string(),
- hir::LitByteStr(ref data) => format!("{:?}", data),
- hir::LitByte(b) => {
+ ast::LitStr(ref st, _) => st.to_string(),
+ ast::LitByteStr(ref data) => format!("{:?}", data),
+ ast::LitByte(b) => {
let mut res = String::from("b'");
for c in (b as char).escape_default() {
res.push(c);
res.push('\'');
res
},
- hir::LitChar(c) => format!("'{}'", c),
- hir::LitInt(i, _t) => i.to_string(),
- hir::LitFloat(ref f, _t) => f.to_string(),
- hir::LitFloatUnsuffixed(ref f) => f.to_string(),
- hir::LitBool(b) => b.to_string(),
+ ast::LitChar(c) => format!("'{}'", c),
+ ast::LitInt(i, _t) => i.to_string(),
+ ast::LitFloat(ref f, _t) => f.to_string(),
+ ast::LitFloatUnsuffixed(ref f) => f.to_string(),
+ ast::LitBool(b) => b.to_string(),
}
}
PatStruct(ref name, ref fields, etc) => {
format!("{} {{ {}{} }}", path_to_string(name),
fields.iter().map(|&Spanned { node: ref fp, .. }|
- format!("{}: {}", fp.ident, name_from_pat(&*fp.pat)))
+ format!("{}: {}", fp.name, name_from_pat(&*fp.pat)))
.collect::<Vec<String>>().join(", "),
if etc { ", ..." } else { "" }
)
fn resolve_type(cx: &DocContext,
path: Path,
id: ast::NodeId) -> Type {
+ debug!("resolve_type({:?},{:?})", path, id);
let tcx = match cx.tcx_opt() {
Some(tcx) => tcx,
// If we're extracting tests, this return value doesn't matter.
None => return Primitive(Bool),
};
- debug!("searching for {} in defmap", id);
let def = match tcx.def_map.borrow().get(&id) {
Some(k) => k.full_def(),
None => panic!("unresolved id not in defmap")
};
+ debug!("resolve_type: def={:?}", def);
+
let is_generic = match def {
def::DefPrimTy(p) => match p {
hir::TyStr => return Primitive(Str),
hir::TyBool => return Primitive(Bool),
hir::TyChar => return Primitive(Char),
- hir::TyInt(hir::TyIs) => return Primitive(Isize),
- hir::TyInt(hir::TyI8) => return Primitive(I8),
- hir::TyInt(hir::TyI16) => return Primitive(I16),
- hir::TyInt(hir::TyI32) => return Primitive(I32),
- hir::TyInt(hir::TyI64) => return Primitive(I64),
- hir::TyUint(hir::TyUs) => return Primitive(Usize),
- hir::TyUint(hir::TyU8) => return Primitive(U8),
- hir::TyUint(hir::TyU16) => return Primitive(U16),
- hir::TyUint(hir::TyU32) => return Primitive(U32),
- hir::TyUint(hir::TyU64) => return Primitive(U64),
- hir::TyFloat(hir::TyF32) => return Primitive(F32),
- hir::TyFloat(hir::TyF64) => return Primitive(F64),
+ hir::TyInt(ast::TyIs) => return Primitive(Isize),
+ hir::TyInt(ast::TyI8) => return Primitive(I8),
+ hir::TyInt(ast::TyI16) => return Primitive(I16),
+ hir::TyInt(ast::TyI32) => return Primitive(I32),
+ hir::TyInt(ast::TyI64) => return Primitive(I64),
+ hir::TyUint(ast::TyUs) => return Primitive(Usize),
+ hir::TyUint(ast::TyU8) => return Primitive(U8),
+ hir::TyUint(ast::TyU16) => return Primitive(U16),
+ hir::TyUint(ast::TyU32) => return Primitive(U32),
+ hir::TyUint(ast::TyU64) => return Primitive(U64),
+ hir::TyFloat(ast::TyF32) => return Primitive(F32),
+ hir::TyFloat(ast::TyF64) => return Primitive(F64),
},
def::DefSelfTy(..) if path.segments.len() == 1 => {
return Generic(special_idents::type_self.name.to_string());
}
fn register_def(cx: &DocContext, def: def::Def) -> DefId {
+ debug!("register_def({:?})", def);
+
let (did, kind) = match def {
def::DefFn(i, _) => (i, TypeFunction),
def::DefTy(i, false) => (i, TypeTypedef),
def::DefMod(i) => (i, TypeModule),
def::DefStatic(i, _) => (i, TypeStatic),
def::DefVariant(i, _, _) => (i, TypeEnum),
+ def::DefSelfTy(Some(def_id), _) => (def_id, TypeTrait),
+ def::DefSelfTy(_, Some((impl_id, _))) => return cx.map.local_def_id(impl_id),
_ => return def.def_id()
};
if did.is_local() { return did }
source: self.whence.clean(cx),
visibility: hir::Public.clean(cx),
stability: self.stab.clean(cx),
- def_id: DefId::local(self.id),
+ def_id: cx.map.local_def_id(self.id),
inner: MacroItem(Macro {
source: self.whence.to_src(cx),
imported_from: self.imported_from.clean(cx),
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Stability {
- pub level: attr::StabilityLevel,
+ pub level: stability::StabilityLevel,
pub feature: String,
pub since: String,
pub deprecated_since: String,
impl Clean<Stability> for attr::Stability {
fn clean(&self, _: &DocContext) -> Stability {
Stability {
- level: self.level,
+ level: stability::StabilityLevel::from_attr_level(&self.level),
feature: self.feature.to_string(),
- since: self.since.as_ref().map_or("".to_string(),
- |interned| interned.to_string()),
- deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
- |istr| istr.to_string()),
- reason: self.reason.as_ref().map_or("".to_string(),
- |interned| interned.to_string()),
- issue: self.issue,
+ since: match self.level {
+ attr::Stable {ref since} => since.to_string(),
+ _ => "".to_string(),
+ },
+ deprecated_since: match self.depr {
+ Some(attr::Deprecation {ref since, ..}) => since.to_string(),
+ _=> "".to_string(),
+ },
+ reason: {
+ if let Some(ref depr) = self.depr {
+ depr.reason.to_string()
+ } else if let attr::Unstable {reason: Some(ref reason), ..} = self.level {
+ reason.to_string()
+ } else {
+ "".to_string()
+ }
+ },
+ issue: match self.level {
+ attr::Unstable {issue, ..} => Some(issue),
+ _ => None,
+ }
}
}
}
impl<'a> Clean<Stability> for &'a attr::Stability {
- fn clean(&self, _: &DocContext) -> Stability {
- Stability {
- level: self.level,
- feature: self.feature.to_string(),
- since: self.since.as_ref().map_or("".to_string(),
- |interned| interned.to_string()),
- deprecated_since: self.deprecated_since.as_ref().map_or("".to_string(),
- |istr| istr.to_string()),
- reason: self.reason.as_ref().map_or("".to_string(),
- |interned| interned.to_string()),
- issue: self.issue,
- }
+ fn clean(&self, dc: &DocContext) -> Stability {
+ (**self).clean(dc)
}
}
impl Clean<TypeBinding> for hir::TypeBinding {
fn clean(&self, cx: &DocContext) -> TypeBinding {
TypeBinding {
- name: self.ident.clean(cx),
+ name: self.name.clean(cx),
ty: self.ty.clean(cx)
}
}
use rustc_driver::{driver, target_features};
use rustc::session::{self, config};
use rustc::middle::def_id::DefId;
-use rustc::middle::{privacy, ty};
+use rustc::middle::ty;
use rustc::front::map as hir_map;
use rustc::lint;
+use rustc::util::nodemap::DefIdSet;
use rustc_trans::back::link;
use rustc_resolve as resolve;
-use rustc_front::lowering::lower_crate;
-use rustc_front::hir;
+use rustc_front::lowering::{lower_crate, LoweringContext};
use syntax::{ast, codemap, diagnostic};
use syntax::feature_gate::UnstableFeatures;
/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
pub enum MaybeTyped<'a, 'tcx: 'a> {
Typed(&'a ty::ctxt<'tcx>),
- NotTyped(session::Session)
+ NotTyped(&'a session::Session)
}
pub type ExternalPaths = RefCell<Option<HashMap<DefId,
(Vec<String>, clean::TypeKind)>>>;
pub struct DocContext<'a, 'tcx: 'a> {
- pub krate: &'tcx hir::Crate,
+ pub map: &'a hir_map::Map<'tcx>,
pub maybe_typed: MaybeTyped<'a, 'tcx>,
pub input: Input,
pub external_paths: ExternalPaths,
}
pub struct CrateAnalysis {
- pub exported_items: privacy::ExportedItems,
- pub public_items: privacy::PublicItems,
+ pub exported_items: DefIdSet,
+ pub public_items: DefIdSet,
pub external_paths: ExternalPaths,
pub external_typarams: RefCell<Option<HashMap<DefId, String>>>,
pub inlined: RefCell<Option<HashSet<DefId>>>,
let krate = driver::assign_node_ids(&sess, krate);
// Lower ast -> hir.
- let mut hir_forest = hir_map::Forest::new(lower_crate(&krate));
+ let lcx = LoweringContext::new(&sess, Some(&krate));
+ let mut hir_forest = hir_map::Forest::new(lower_crate(&lcx, &krate));
let arenas = ty::CtxtArenas::new();
let hir_map = driver::make_map(&sess, &mut hir_forest);
- driver::phase_3_run_analysis_passes(sess,
+ driver::phase_3_run_analysis_passes(&sess,
hir_map,
- &krate,
&arenas,
- name,
+ &name,
resolve::MakeGlobMap::No,
|tcx, analysis| {
let ty::CrateAnalysis { exported_items, public_items, .. } = analysis;
+ // Convert from a NodeId set to a DefId set since we don't always have easy access
+ // to the map from defid -> nodeid
+ let exported_items: DefIdSet =
+ exported_items.into_iter()
+ .map(|n| tcx.map.local_def_id(n))
+ .collect();
+ let public_items: DefIdSet =
+ public_items.into_iter()
+ .map(|n| tcx.map.local_def_id(n))
+ .collect();
+
let ctxt = DocContext {
- krate: tcx.map.krate(),
+ map: &tcx.map,
maybe_typed: Typed(tcx),
input: input,
external_traits: RefCell::new(Some(HashMap::new())),
populated_crate_impls: RefCell::new(HashSet::new()),
deref_trait_did: Cell::new(None),
};
- debug!("crate: {:?}", ctxt.krate);
+ debug!("crate: {:?}", ctxt.map.krate());
let mut analysis = CrateAnalysis {
exported_items: exported_items,
let krate = {
let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
- v.visit(ctxt.krate);
+ v.visit(ctxt.map.krate());
v.clean(&ctxt)
};
*analysis.inlined.borrow_mut() = map;
analysis.deref_trait_did = ctxt.deref_trait_did.get();
(krate, analysis)
- }).1
+ })
}
use syntax::codemap::Span;
use syntax::abi;
use syntax::ast;
-use syntax::ast::{Ident, NodeId};
+use syntax::ast::{Name, NodeId};
+use syntax::attr;
use syntax::ptr::P;
use rustc_front::hir;
-use rustc_front::attr;
pub struct Module {
- pub name: Option<Ident>,
- pub attrs: Vec<hir::Attribute>,
+ pub name: Option<Name>,
+ pub attrs: Vec<ast::Attribute>,
pub where_outer: Span,
pub where_inner: Span,
pub extern_crates: Vec<ExternCrate>,
}
impl Module {
- pub fn new(name: Option<Ident>) -> Module {
+ pub fn new(name: Option<Name>) -> Module {
Module {
name : name,
id: 0,
pub stab: Option<attr::Stability>,
pub id: NodeId,
pub struct_type: StructType,
- pub name: Ident,
+ pub name: Name,
pub generics: hir::Generics,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub fields: Vec<hir::StructField>,
pub whence: Span,
}
pub stab: Option<attr::Stability>,
pub variants: Vec<Variant>,
pub generics: hir::Generics,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub id: NodeId,
pub whence: Span,
- pub name: Ident,
+ pub name: Name,
}
pub struct Variant {
- pub name: Ident,
- pub attrs: Vec<hir::Attribute>,
- pub kind: hir::VariantKind,
- pub id: ast::NodeId,
- pub vis: hir::Visibility,
+ pub name: Name,
+ pub attrs: Vec<ast::Attribute>,
+ pub def: hir::VariantData,
pub stab: Option<attr::Stability>,
pub whence: Span,
}
pub struct Function {
pub decl: hir::FnDecl,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub id: NodeId,
- pub name: Ident,
+ pub name: Name,
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub unsafety: hir::Unsafety,
pub struct Typedef {
pub ty: P<hir::Ty>,
pub gen: hir::Generics,
- pub name: Ident,
+ pub name: Name,
pub id: ast::NodeId,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub whence: Span,
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub type_: P<hir::Ty>,
pub mutability: hir::Mutability,
pub expr: P<hir::Expr>,
- pub name: Ident,
- pub attrs: Vec<hir::Attribute>,
+ pub name: Name,
+ pub attrs: Vec<ast::Attribute>,
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub id: ast::NodeId,
pub struct Constant {
pub type_: P<hir::Ty>,
pub expr: P<hir::Expr>,
- pub name: Ident,
- pub attrs: Vec<hir::Attribute>,
+ pub name: Name,
+ pub attrs: Vec<ast::Attribute>,
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub id: ast::NodeId,
pub struct Trait {
pub unsafety: hir::Unsafety,
- pub name: Ident,
+ pub name: Name,
pub items: Vec<P<hir::TraitItem>>, //should be TraitItem
pub generics: hir::Generics,
pub bounds: Vec<hir::TyParamBound>,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub id: ast::NodeId,
pub whence: Span,
pub vis: hir::Visibility,
pub trait_: Option<hir::TraitRef>,
pub for_: P<hir::Ty>,
pub items: Vec<P<hir::ImplItem>>,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub whence: Span,
pub vis: hir::Visibility,
pub stab: Option<attr::Stability>,
pub unsafety: hir::Unsafety,
pub trait_: hir::TraitRef,
pub id: ast::NodeId,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub whence: Span,
}
pub struct Macro {
- pub name: Ident,
+ pub name: Name,
pub id: ast::NodeId,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub whence: Span,
pub stab: Option<attr::Stability>,
- pub imported_from: Option<Ident>,
+ pub imported_from: Option<Name>,
}
pub struct ExternCrate {
- pub name: Ident,
+ pub name: Name,
pub path: Option<String>,
pub vis: hir::Visibility,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub whence: Span,
}
pub struct Import {
pub id: NodeId,
pub vis: hir::Visibility,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub node: hir::ViewPath_,
pub whence: Span,
}
-pub fn struct_type_from_def(sd: &hir::StructDef) -> StructType {
- if sd.ctor_id.is_some() {
+pub fn struct_type_from_def(sd: &hir::VariantData) -> StructType {
+ if !sd.is_struct() {
// We are in a tuple-struct
- match sd.fields.len() {
+ match sd.fields().len() {
0 => Unit,
1 => Newtype,
_ => Tuple
use std::fmt;
use std::iter::repeat;
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
+use rustc::metadata::cstore::LOCAL_CRATE;
+use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
use syntax::abi::Abi;
-use syntax::ast;
use rustc_front::hir;
use clean;
Some(&cnum) => {
let path = &m.paths[&DefId {
krate: cnum,
- node: ast::CRATE_NODE_ID,
+ index: CRATE_DEF_INDEX,
}];
let loc = match m.extern_locations[&cnum] {
(_, render::Remote(ref s)) => Some(s.to_string()),
///
/// Any leading or trailing whitespace will be trimmed.
fn collapse_whitespace(s: &str) -> String {
- s.split(|c: char| c.is_whitespace()).filter(|s| {
- !s.is_empty()
- }).collect::<Vec<_>>().join(" ")
+ s.split_whitespace().collect::<Vec<_>>().join(" ")
}
thread_local!(static USED_HEADER_MAP: RefCell<HashMap<String, usize>> = {
// Extract the text provided
let s = if text.is_null() {
- "".to_string()
+ "".to_owned()
} else {
let s = unsafe { (*text).as_bytes() };
- str::from_utf8(s).unwrap().to_string()
+ str::from_utf8(&s).unwrap().to_owned()
};
- // Transform the contents of the header into a hyphenated string
- let id = s.split_whitespace().map(|s| s.to_ascii_lowercase())
- .collect::<Vec<String>>().join("-");
-
+ // Discard '<em>', '<code>' tags and some escaped characters,
+ // transform the contents of the header into a hyphenated string
+ // without non-alphanumeric characters other than '-' and '_'.
+ //
// This is a terrible hack working around how hoedown gives us rendered
// html for text rather than the raw text.
+ let mut id = s.clone();
+ let repl_sub = vec!["<em>", "</em>", "<code>", "</code>",
+ "<strong>", "</strong>",
+ "<", ">", "&", "'", """];
+ for sub in repl_sub {
+ id = id.replace(sub, "");
+ }
+ let id = id.chars().filter_map(|c| {
+ if c.is_alphanumeric() || c == '-' || c == '_' {
+ if c.is_ascii() {
+ Some(c.to_ascii_lowercase())
+ } else {
+ Some(c)
+ }
+ } else if c.is_whitespace() && c.is_ascii() {
+ Some('-')
+ } else {
+ None
+ }
+ }).collect::<String>();
let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state };
let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
// Make sure our hyphenated ID is unique for this page
let id = USED_HEADER_MAP.with(|map| {
- let id = id.replace("<code>", "").replace("</code>", "").to_string();
let id = match map.borrow_mut().get_mut(&id) {
None => id,
Some(a) => { *a += 1; format!("{}-{}", id, *a - 1) }
id
});
- let sec = match opaque.toc_builder {
- Some(ref mut builder) => {
- builder.push(level as u32, s.clone(), id.clone())
- }
- None => {""}
- };
+
+ let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| {
+ format!("{} ", builder.push(level as u32, s.clone(), id.clone()))
+ });
// Render the HTML
- let text = format!(r##"<h{lvl} id="{id}" class='section-header'><a
- href="#{id}">{sec}{}</a></h{lvl}>"##,
- s, lvl = level, id = id,
- sec = if sec.is_empty() {
- sec.to_string()
- } else {
- format!("{} ", sec)
- });
+ let text = format!("<h{lvl} id='{id}' class='section-header'>\
+ <a href='#{id}'>{sec}{}</a></h{lvl}>",
+ s, lvl = level, id = id, sec = sec);
let text = CString::new(text).unwrap();
unsafe { hoedown_buffer_puts(ob, text.as_ptr()) }
_: *const hoedown_renderer_data,
) -> libc::c_int {
let content = if text.is_null() {
- "".to_string()
+ "".to_owned()
} else {
let bytes = unsafe { (*text).as_bytes() };
let s = str::from_utf8(bytes).unwrap();
hoedown_html_renderer_free(renderer);
- let mut ret = match opaque.toc_builder {
- Some(b) => write!(w, "<nav id=\"TOC\">{}</nav>", b.into_toc()),
- None => Ok(())
- };
+ let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| {
+ write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc())
+ });
if ret.is_ok() {
let buf = (*ob).as_bytes();
stripped_filtered_line(l).unwrap_or(l)
});
let text = lines.collect::<Vec<&str>>().join("\n");
- tests.add_test(text.to_string(),
+ tests.add_test(text.to_owned(),
block_info.should_panic, block_info.no_run,
block_info.ignore, block_info.test_harness);
}
md.len() as libc::size_t);
hoedown_document_free(document);
let plain_slice = (*ob).as_bytes();
- let plain = match str::from_utf8(plain_slice) {
- Ok(s) => s.to_string(),
- Err(_) => "".to_string(),
- };
+ let plain = str::from_utf8(plain_slice).unwrap_or("").to_owned();
hoedown_buffer_free(ob);
plain
}
#[cfg(test)]
mod tests {
use super::{LangString, Markdown};
- use super::{collapse_whitespace, plain_summary_line};
+ use super::plain_summary_line;
#[test]
fn test_lang_string_parse() {
format!("{}", Markdown(markdown));
}
+ #[test]
+ fn test_header() {
+ fn t(input: &str, expect: &str) {
+ let output = format!("{}", Markdown(input));
+ assert_eq!(output, expect);
+ }
+
+ t("# Foo bar", "\n<h1 id='foo-bar' class='section-header'>\
+ <a href='#foo-bar'>Foo bar</a></h1>");
+ t("## Foo-bar_baz qux", "\n<h2 id='foo-bar_baz-qux' class=\'section-\
+ header'><a href='#foo-bar_baz-qux'>Foo-bar_baz qux</a></h2>");
+ t("### **Foo** *bar* baz!?!& -_qux_-%",
+ "\n<h3 id='foo-bar-baz--_qux_-' class='section-header'>\
+ <a href='#foo-bar-baz--_qux_-'><strong>Foo</strong> \
+ <em>bar</em> baz!?!& -_qux_-%</a></h3>");
+ t("####**Foo?** & \\*bar?!* _`baz`_ ❤ #qux",
+ "\n<h4 id='foo--bar--baz--qux' class='section-header'>\
+ <a href='#foo--bar--baz--qux'><strong>Foo?</strong> & *bar?!* \
+ <em><code>baz</code></em> ❤ #qux</a></h4>");
+ }
+
#[test]
fn test_plain_summary_line() {
fn t(input: &str, expect: &str) {
t("# top header", "top header");
t("## header", "header");
}
-
- #[test]
- fn test_collapse_whitespace() {
- fn t(input: &str, expected: &str) {
- let actual = collapse_whitespace(input);
- assert_eq!(actual, expected);
- }
-
- t("foo", "foo");
- t("foo bar baz", "foo bar baz");
- t(" foo bar", "foo bar");
- t("\tfoo bar\nbaz", "foo bar baz");
- t("foo bar \n baz\t\tqux\n", "foo bar baz qux");
- }
}
use std::cmp::Ordering;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::default::Default;
-use std::fmt;
+use std::error;
+use std::fmt::{self, Display, Formatter};
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufWriter, BufReader};
use serialize::json::{self, ToJson};
use syntax::{abi, ast};
-use rustc::middle::def_id::{DefId, LOCAL_CRATE};
-use rustc::util::nodemap::NodeSet;
-use rustc_front::{hir, attr};
+use rustc::metadata::cstore::LOCAL_CRATE;
+use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
+use rustc::middle::stability;
+use rustc::util::nodemap::DefIdSet;
+use rustc_front::hir;
use clean::{self, SelfTy};
use doctree;
}
}
+#[derive(Debug)]
+pub struct Error {
+ file: PathBuf,
+ error: io::Error,
+}
+
+impl error::Error for Error {
+ fn description(&self) -> &str {
+ self.error.description()
+ }
+}
+
+impl Display for Error {
+ fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+ write!(f, "\"{}\": {}", self.file.display(), self.error)
+ }
+}
+
+impl Error {
+ pub fn new(e: io::Error, file: &Path) -> Error {
+ Error {
+ file: file.to_path_buf(),
+ error: e,
+ }
+ }
+}
+
+macro_rules! try_err {
+ ($e:expr, $file:expr) => ({
+ match $e {
+ Ok(e) => e,
+ Err(e) => return Err(Error::new(e, $file)),
+ }
+ })
+}
+
/// This cache is used to store information about the `clean::Crate` being
/// rendered in order to provide more useful documentation. This contains
/// information like all implementors of a trait, all traits a type implements,
search_index: Vec<IndexItem>,
privmod: bool,
remove_priv: bool,
- public_items: NodeSet,
+ public_items: DefIdSet,
deref_trait_did: Option<DefId>,
// In rare case where a structure is defined in one module but implemented
// then the fully qualified name of the structure isn't presented in `paths`
// yet when its implementation methods are being indexed. Caches such methods
// and their parent id here and indexes them at the end of crate parsing.
- orphan_methods: Vec<(ast::NodeId, clean::Item)>,
+ orphan_methods: Vec<(DefId, clean::Item)>,
}
/// Helper struct to render all source code to HTML pages
pub fn run(mut krate: clean::Crate,
external_html: &ExternalHtml,
dst: PathBuf,
- passes: HashSet<String>) -> io::Result<()> {
+ passes: HashSet<String>) -> Result<(), Error> {
let src_root = match krate.src.parent() {
Some(p) => p.to_path_buf(),
None => PathBuf::new(),
issue_tracker_base_url: None,
};
- try!(mkdir(&cx.dst));
+ try_err!(mkdir(&cx.dst), &cx.dst);
// Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML
let analysis = ::ANALYSISKEY.with(|a| a.clone());
let analysis = analysis.borrow();
let public_items = analysis.as_ref().map(|a| a.public_items.clone());
- let public_items = public_items.unwrap_or(NodeSet());
+ let public_items = public_items.unwrap_or(DefIdSet());
let paths: HashMap<DefId, (Vec<String>, ItemType)> =
analysis.as_ref().map(|a| {
let paths = a.external_paths.borrow_mut().take().unwrap();
for &(n, ref e) in &krate.externs {
cache.extern_locations.insert(n, (e.name.clone(),
extern_location(e, &cx.dst)));
- let did = DefId { krate: n, node: ast::CRATE_NODE_ID };
+ let did = DefId { krate: n, index: CRATE_DEF_INDEX };
cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
}
krate = cache.fold_crate(krate);
// Build our search index
- let index = try!(build_index(&krate, &mut cache));
+ let index = build_index(&krate, &mut cache);
// Freeze the cache now that the index has been built. Put an Arc into TLS
// for future parallelization opportunities
cx.krate(krate)
}
-fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::Result<String> {
+fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
// Build the search index from the collected metadata
let mut nodeid_to_pathid = HashMap::new();
let mut pathid_to_nodeid = Vec::new();
// Attach all orphan methods to the type's definition if the type
// has since been learned.
- for &(pid, ref item) in orphan_methods {
- let did = DefId::local(pid);
+ for &(did, ref item) in orphan_methods {
match paths.get(&did) {
Some(&(ref fqp, _)) => {
// Needed to determine `self` type.
},
None => {}
}
- };
+ }
// Reduce `NodeId` in paths into smaller sequential numbers,
// and prune the paths that do not appear in the index.
// Collect the index into a string
let mut w = io::Cursor::new(Vec::new());
- try!(write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name));
+ write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name).unwrap();
let mut lastpath = "".to_string();
for (i, item) in cache.search_index.iter().enumerate() {
};
if i > 0 {
- try!(write!(&mut w, ","));
+ write!(&mut w, ",").unwrap();
}
- try!(write!(&mut w, r#"[{},"{}","{}",{}"#,
- item.ty as usize, item.name, path,
- item.desc.to_json().to_string()));
+ write!(&mut w, r#"[{},"{}","{}",{}"#,
+ item.ty as usize, item.name, path,
+ item.desc.to_json().to_string()).unwrap();
match item.parent {
Some(nodeid) => {
let pathid = *nodeid_to_pathid.get(&nodeid).unwrap();
- try!(write!(&mut w, ",{}", pathid));
+ write!(&mut w, ",{}", pathid).unwrap();
}
- None => try!(write!(&mut w, ",null"))
+ None => write!(&mut w, ",null").unwrap()
}
match item.search_type {
- Some(ref t) => try!(write!(&mut w, ",{}", t)),
- None => try!(write!(&mut w, ",null"))
+ Some(ref t) => write!(&mut w, ",{}", t).unwrap(),
+ None => write!(&mut w, ",null").unwrap()
}
- try!(write!(&mut w, "]"));
+ write!(&mut w, "]").unwrap();
}
- try!(write!(&mut w, r#"],"paths":["#));
+ write!(&mut w, r#"],"paths":["#).unwrap();
for (i, &did) in pathid_to_nodeid.iter().enumerate() {
let &(ref fqp, short) = cache.paths.get(&did).unwrap();
if i > 0 {
- try!(write!(&mut w, ","));
+ write!(&mut w, ",").unwrap();
}
- try!(write!(&mut w, r#"[{},"{}"]"#,
- short as usize, *fqp.last().unwrap()));
+ write!(&mut w, r#"[{},"{}"]"#,
+ short as usize, *fqp.last().unwrap()).unwrap();
}
- try!(write!(&mut w, "]}};"));
+ write!(&mut w, "]}};").unwrap();
- Ok(String::from_utf8(w.into_inner()).unwrap())
+ String::from_utf8(w.into_inner()).unwrap()
}
fn write_shared(cx: &Context,
krate: &clean::Crate,
cache: &Cache,
- search_index: String) -> io::Result<()> {
+ search_index: String) -> Result<(), Error> {
// Write out the shared files. Note that these are shared among all rustdoc
// docs placed in the output directory, so this needs to be a synchronized
// operation with respect to all other rustdocs running around.
- try!(mkdir(&cx.dst));
+ try_err!(mkdir(&cx.dst), &cx.dst);
let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
// Add all the static files. These may already exist, but we just
// overwrite them anyway to make sure that they're fresh and up-to-date.
try!(write(cx.dst.join("jquery.js"),
include_bytes!("static/jquery-2.1.4.min.js")));
- try!(write(cx.dst.join("main.js"), include_bytes!("static/main.js")));
- try!(write(cx.dst.join("playpen.js"), include_bytes!("static/playpen.js")));
- try!(write(cx.dst.join("main.css"), include_bytes!("static/main.css")));
+ try!(write(cx.dst.join("main.js"),
+ include_bytes!("static/main.js")));
+ try!(write(cx.dst.join("playpen.js"),
+ include_bytes!("static/playpen.js")));
+ try!(write(cx.dst.join("main.css"),
+ include_bytes!("static/main.css")));
try!(write(cx.dst.join("normalize.css"),
include_bytes!("static/normalize.css")));
try!(write(cx.dst.join("FiraSans-Regular.woff"),
include_bytes!("static/FiraSans-Regular.woff")));
try!(write(cx.dst.join("FiraSans-Medium.woff"),
include_bytes!("static/FiraSans-Medium.woff")));
+ try!(write(cx.dst.join("FiraSans-LICENSE.txt"),
+ include_bytes!("static/FiraSans-LICENSE.txt")));
try!(write(cx.dst.join("Heuristica-Italic.woff"),
include_bytes!("static/Heuristica-Italic.woff")));
+ try!(write(cx.dst.join("Heuristica-LICENSE.txt"),
+ include_bytes!("static/Heuristica-LICENSE.txt")));
try!(write(cx.dst.join("SourceSerifPro-Regular.woff"),
include_bytes!("static/SourceSerifPro-Regular.woff")));
try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
include_bytes!("static/SourceSerifPro-Bold.woff")));
+ try!(write(cx.dst.join("SourceSerifPro-LICENSE.txt"),
+ include_bytes!("static/SourceSerifPro-LICENSE.txt")));
try!(write(cx.dst.join("SourceCodePro-Regular.woff"),
include_bytes!("static/SourceCodePro-Regular.woff")));
try!(write(cx.dst.join("SourceCodePro-Semibold.woff"),
include_bytes!("static/SourceCodePro-Semibold.woff")));
+ try!(write(cx.dst.join("SourceCodePro-LICENSE.txt"),
+ include_bytes!("static/SourceCodePro-LICENSE.txt")));
+ try!(write(cx.dst.join("LICENSE-MIT.txt"),
+ include_bytes!("static/LICENSE-MIT.txt")));
+ try!(write(cx.dst.join("LICENSE-APACHE.txt"),
+ include_bytes!("static/LICENSE-APACHE.txt")));
+ try!(write(cx.dst.join("COPYRIGHT.txt"),
+ include_bytes!("static/COPYRIGHT.txt")));
fn collect(path: &Path, krate: &str,
key: &str) -> io::Result<Vec<String>> {
// Update the search index
let dst = cx.dst.join("search-index.js");
- let all_indexes = try!(collect(&dst, &krate.name, "searchIndex"));
- let mut w = try!(File::create(&dst));
- try!(writeln!(&mut w, "var searchIndex = {{}};"));
- try!(writeln!(&mut w, "{}", search_index));
+ let all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
+ let mut w = try_err!(File::create(&dst), &dst);
+ try_err!(writeln!(&mut w, "var searchIndex = {{}};"), &dst);
+ try_err!(writeln!(&mut w, "{}", search_index), &dst);
for index in &all_indexes {
- try!(writeln!(&mut w, "{}", *index));
+ try_err!(writeln!(&mut w, "{}", *index), &dst);
}
- try!(writeln!(&mut w, "initSearch(searchIndex);"));
+ try_err!(writeln!(&mut w, "initSearch(searchIndex);"), &dst);
// Update the list of all implementors for traits
let dst = cx.dst.join("implementors");
- try!(mkdir(&dst));
+ try_err!(mkdir(&dst), &dst);
for (&did, imps) in &cache.implementors {
// Private modules can leak through to this phase of rustdoc, which
// could contain implementations for otherwise private types. In some
let mut mydst = dst.clone();
for part in &remote_path[..remote_path.len() - 1] {
mydst.push(part);
- try!(mkdir(&mydst));
+ try_err!(mkdir(&mydst), &mydst);
}
mydst.push(&format!("{}.{}.js",
remote_item_type.to_static_str(),
remote_path[remote_path.len() - 1]));
- let all_implementors = try!(collect(&mydst, &krate.name,
- "implementors"));
+ let all_implementors = try_err!(collect(&mydst, &krate.name,
+ "implementors"),
+ &mydst);
- try!(mkdir(mydst.parent().unwrap()));
- let mut f = BufWriter::new(try!(File::create(&mydst)));
- try!(writeln!(&mut f, "(function() {{var implementors = {{}};"));
+ try_err!(mkdir(mydst.parent().unwrap()),
+ &mydst.parent().unwrap().to_path_buf());
+ let mut f = BufWriter::new(try_err!(File::create(&mydst), &mydst));
+ try_err!(writeln!(&mut f, "(function() {{var implementors = {{}};"), &mydst);
for implementor in &all_implementors {
- try!(write!(&mut f, "{}", *implementor));
+ try_err!(write!(&mut f, "{}", *implementor), &mydst);
}
- try!(write!(&mut f, r"implementors['{}'] = [", krate.name));
+ try_err!(write!(&mut f, r"implementors['{}'] = [", krate.name), &mydst);
for imp in imps {
// If the trait and implementation are in the same crate, then
// there's no need to emit information about it (there's inlining
// going on). If they're in different crates then the crate defining
// the trait will be interested in our implementation.
if imp.def_id.krate == did.krate { continue }
- try!(write!(&mut f, r#""{}","#, imp.impl_));
+ try_err!(write!(&mut f, r#""{}","#, imp.impl_), &mydst);
}
- try!(writeln!(&mut f, r"];"));
- try!(writeln!(&mut f, "{}", r"
+ try_err!(writeln!(&mut f, r"];"), &mydst);
+ try_err!(writeln!(&mut f, "{}", r"
if (window.register_implementors) {
window.register_implementors(implementors);
} else {
window.pending_implementors = implementors;
}
- "));
- try!(writeln!(&mut f, r"}})()"));
+ "), &mydst);
+ try_err!(writeln!(&mut f, r"}})()"), &mydst);
}
Ok(())
}
fn render_sources(cx: &mut Context,
- krate: clean::Crate) -> io::Result<clean::Crate> {
+ krate: clean::Crate) -> Result<clean::Crate, Error> {
info!("emitting source files");
let dst = cx.dst.join("src");
- try!(mkdir(&dst));
+ try_err!(mkdir(&dst), &dst);
let dst = dst.join(&krate.name);
- try!(mkdir(&dst));
+ try_err!(mkdir(&dst), &dst);
let mut folder = SourceCollector {
dst: dst,
seen: HashSet::new(),
/// Writes the entire contents of a string to a destination, not attempting to
/// catch any errors.
-fn write(dst: PathBuf, contents: &[u8]) -> io::Result<()> {
- try!(File::create(&dst)).write_all(contents)
+fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> {
+ Ok(try_err!(try_err!(File::create(&dst), &dst).write_all(contents), &dst))
}
/// Makes a directory on the filesystem, failing the thread if an error occurs and
fname.push(".html");
cur.push(&fname[..]);
let mut w = BufWriter::new(try!(File::create(&cur)));
-
let title = format!("{} -- source", cur.file_name().unwrap()
.to_string_lossy());
let desc = format!("Source to the Rust file `{}`.", filename);
if parent.is_local() {
// We have a parent, but we don't know where they're
// defined yet. Wait for later to index this item.
- self.orphan_methods.push((parent.node, item.clone()))
+ self.orphan_methods.push((parent, item.clone()))
}
}
_ => {}
// `public_items` map, so we can skip inserting into the
// paths map if there was already an entry present and we're
// not a public item.
- let id = item.def_id.node;
- if !self.paths.contains_key(&item.def_id) ||
- !item.def_id.is_local() ||
- self.public_items.contains(&id) {
+ if
+ !self.paths.contains_key(&item.def_id) ||
+ !item.def_id.is_local() ||
+ self.public_items.contains(&item.def_id)
+ {
self.paths.insert(item.def_id,
(self.stack.clone(), shortty(&item)));
}
ref t => {
match t.primitive_type() {
Some(prim) => {
- let did = DefId::local(prim.to_node_id());
+ let did = DefId::local(prim.to_def_index());
self.parent_stack.push(did);
true
}
ref t => {
t.primitive_type().and_then(|t| {
self.primitive_locations.get(&t).map(|n| {
- let id = t.to_node_id();
- DefId { krate: *n, node: id }
+ let id = t.to_def_index();
+ DefId { krate: *n, index: id }
})
})
}
///
/// This currently isn't parallelized, but it'd be pretty easy to add
/// parallelization to this function.
- fn krate(self, mut krate: clean::Crate) -> io::Result<()> {
+ fn krate(self, mut krate: clean::Crate) -> Result<(), Error> {
let mut item = match krate.module.take() {
Some(i) => i,
None => return Ok(())
/// all sub-items which need to be rendered.
///
/// The rendering driver uses this closure to queue up more work.
- fn item<F>(&mut self, item: clean::Item, mut f: F) -> io::Result<()> where
+ fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
F: FnMut(&mut Context, clean::Item),
{
fn render(w: File, cx: &Context, it: &clean::Item,
let mut item = Some(item);
self.recurse(name, |this| {
let item = item.take().unwrap();
- let dst = this.dst.join("index.html");
- let dst = try!(File::create(&dst));
- try!(render(dst, this, &item, false));
+ let joint_dst = this.dst.join("index.html");
+ let dst = try_err!(File::create(&joint_dst), &joint_dst);
+ try_err!(render(dst, this, &item, false), &joint_dst);
let m = match item.inner {
clean::ModuleItem(m) => m,
{
let items = this.build_sidebar_items(&m);
let js_dst = this.dst.join("sidebar-items.js");
- let mut js_out = BufWriter::new(try!(File::create(&js_dst)));
- try!(write!(&mut js_out, "initSidebarItems({});",
- json::as_json(&items)));
+ let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst));
+ try_err!(write!(&mut js_out, "initSidebarItems({});",
+ json::as_json(&items)), &js_dst);
}
for item in m.items {
// Things which don't have names (like impls) don't get special
// pages dedicated to them.
_ if item.name.is_some() => {
- let dst = self.dst.join(&item_path(&item));
- let dst = try!(File::create(&dst));
- render(dst, self, &item, true)
+ let joint_dst = self.dst.join(&item_path(&item));
+
+ let dst = try_err!(File::create(&joint_dst), &joint_dst);
+ try_err!(render(dst, self, &item, true), &joint_dst);
+ Ok(())
}
_ => Ok(())
root = root,
path = path[..path.len() - 1].join("/"),
file = item_path(self.item),
- goto = self.item.def_id.node))
+ goto = self.item.def_id.index.as_usize()))
}
}
}
Some(l) => {
try!(write!(fmt, "<a id='src-{}' class='srclink' \
href='{}' title='{}'>[src]</a>",
- self.item.def_id.node, l, "goto source code"));
+ self.item.def_id.index.as_usize(), l, "goto source code"));
}
None => {}
}
let s1 = i1.stability.as_ref().map(|s| s.level);
let s2 = i2.stability.as_ref().map(|s| s.level);
match (s1, s2) {
- (Some(attr::Unstable), Some(attr::Stable)) => return Ordering::Greater,
- (Some(attr::Stable), Some(attr::Unstable)) => return Ordering::Less,
+ (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater,
+ (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less,
_ => {}
}
i1.name.cmp(&i2.name)
String::new()
};
format!("Deprecated{}{}", since, Markdown(&reason))
- } else if stab.level == attr::Unstable {
+ } else if stab.level == stability::Unstable {
let unstable_extra = if show_reason {
match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) {
(true, &Some(ref tracker_url), Some(issue_no)) =>
_ => {
if let Some(prim) = target.primitive_type() {
if let Some(c) = cache().primitive_locations.get(&prim) {
- let did = DefId { krate: *c, node: prim.to_node_id() };
+ let did = DefId { krate: *c, index: prim.to_def_index() };
try!(render_assoc_items(w, cx, did, what));
}
}
--- /dev/null
+These documentation pages include resources by third parties. This copyright
+file applies only to those resources. The following third party resources are
+included, and carry their own copyright notices and license terms:
+
+* Fira Sans (FiraSans-Regular.woff, FiraSans-Medium.woff):
+
+ Copyright (c) 2014, Mozilla Foundation https://mozilla.org/
+ with Reserved Font Name Fira Sans.
+
+ Copyright (c) 2014, Telefonica S.A.
+
+ Licensed under the SIL Open Font License, Version 1.1.
+ See FiraSans-LICENSE.txt.
+
+* Heuristica (Heuristica-Italic.woff):
+
+ Copyright 1989, 1991 Adobe Systems Incorporated. All rights reserved.
+ Utopia is either a registered trademark or trademark of Adobe Systems
+ Incorporated in the United States and/or other countries. Used under
+ license.
+
+ Copyright 2006 Han The Thanh, Vntopia font family, http://vntex.sf.net
+
+ Copyright (c) 2008-2012, Andrey V. Panov (panov@canopus.iacp.dvo.ru),
+ with Reserved Font Name Heuristica.
+
+ Licensed under the SIL Open Font License, Version 1.1.
+ See Heuristica-LICENSE.txt.
+
+* jQuery (jquery-2.1.4.min.js):
+
+ Copyright 2005, 2015 jQuery Foundation, Inc.
+ Licensed under the MIT license (see LICENSE-MIT.txt).
+
+* main.css, main.js, and playpen.js:
+
+ Copyright 2015 The Rust Developers.
+ Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or
+ the MIT license (LICENSE-MIT.txt) at your option.
+
+* normalize.css:
+
+ Copyright (c) Nicolas Gallagher and Jonathan Neal.
+ Licensed under the MIT license (see LICENSE-MIT.txt).
+
+* Source Code Pro (SourceCodePro-Regular.woff, SourceCodePro-Semibold.woff):
+
+ Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/),
+ with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark
+ of Adobe Systems Incorporated in the United States and/or other countries.
+
+ Licensed under the SIL Open Font License, Version 1.1.
+ See SourceCodePro-LICENSE.txt.
+
+* Source Serif Pro (SourceSerifPro-Regular.woff, SourceSerifPro-Bold.woff):
+
+ Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/), with
+ Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of
+ Adobe Systems Incorporated in the United States and/or other countries.
+
+ Licensed under the SIL Open Font License, Version 1.1.
+ See SourceSerifPro-LICENSE.txt.
+
+This copyright file is intended to be distributed with rustdoc output.
--- /dev/null
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
--- /dev/null
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
* option. This file may not be copied, modified, or distributed
* except according to those terms.
*/
+
+/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@font-face {
font-family: 'Fira Sans';
font-style: normal;
font-weight: 500;
src: local('Fira Sans Medium'), url("FiraSans-Medium.woff") format('woff');
}
+
+/* See SourceSerifPro-LICENSE.txt for the Source Serif Pro license and
+ * Heuristica-LICENSE.txt for the Heuristica license. */
@font-face {
font-family: 'Source Serif Pro';
font-style: normal;
font-weight: 700;
src: local('Source Serif Pro Bold'), url("SourceSerifPro-Bold.woff") format('woff');
}
+
+/* See SourceCodePro-LICENSE.txt for the Source Code Pro license. */
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
.rusttest { display: none; }
pre.rust { position: relative; }
-.test-arrow {
+a.test-arrow {
display: inline-block;
position: absolute;
- top: 0;
- right: 10px;
- font-size: 150%;
- -webkit-transform: scaleX(-1);
- transform: scaleX(-1);
+
+ background-color: #4e8bca;
+ color: #f5f5f5;
+ padding: 5px 10px 5px 10px;
+ border-radius: 5px;
+ font-size: 130%;
+ top: 5px;
+ right: 5px;
}
.methods .section-header {
}
function browserSupportsHistoryApi() {
- return window.history && typeof window.history.pushState === "function";
+ return document.location.protocol != "file:" &&
+ window.history && typeof window.history.pushState === "function";
}
function highlightSourceLines(ev) {
$(document).on("keypress", handleShortcut);
$(document).on("keydown", handleShortcut);
$(document).on("click", function(ev) {
- if (!$(e.target).closest("#help > div").length) {
+ if (!$(ev.target).closest("#help > div").length) {
$("#help").addClass("hidden");
$("body").removeClass("blur");
}
if ((aaa.item.ty === TY_PRIMITIVE) && (bbb.item.ty !== TY_PRIMITIVE)) {
return -1;
}
+ if ((bbb.item.ty === TY_PRIMITIVE) && (aaa.item.ty !== TY_PRIMITIVE)) {
+ return 1;
+ }
// sort by description (no description goes later)
a = (aaa.item.desc === '');
var $active = $results.filter('.highlighted');
if (e.which === 38) { // up
- e.preventDefault();
if (!$active.length || !$active.prev()) {
return;
}
$active.prev().addClass('highlighted');
$active.removeClass('highlighted');
} else if (e.which === 40) { // down
- e.preventDefault();
if (!$active.length) {
$results.first().addClass('highlighted');
} else if ($active.next().length) {
$active.removeClass('highlighted');
}
} else if (e.which === 13) { // return
- e.preventDefault();
if ($active.length) {
document.location.href = $active.find('a').prop('href');
}
displayPath = item.path + '::';
href = rootPath + item.path.replace(/::/g, '/') +
'/index.html';
+ } else if (type === "primitive") {
+ displayPath = "";
+ href = rootPath + item.path.replace(/::/g, '/') +
+ '/' + type + '.' + name + '.html';
} else if (item.parent !== undefined) {
var myparent = item.parent;
var anchor = '#' + type + '.' + name;
}
function startSearch() {
- var keyUpTimeout;
- $('.do-search').on('click', search);
- $('.search-input').on('keyup', function() {
- clearTimeout(keyUpTimeout);
- keyUpTimeout = setTimeout(search, 500);
+ var searchTimeout;
+ $(".search-input").on("keyup input",function() {
+ clearTimeout(searchTimeout);
+ if ($(this).val().length === 0) {
+ window.history.replaceState("", "std - Rust", "?search=");
+ $('#main.content').removeClass('hidden');
+ $('#search.content').addClass('hidden');
+ } else {
+ searchTimeout = setTimeout(search, 500);
+ }
+ });
+ $('.search-form').on('submit', function(e){
+ e.preventDefault();
+ clearTimeout(searchTimeout);
+ search();
+ });
+ $('.search-input').on('change paste', function(e) {
+ // Do NOT e.preventDefault() here. It will prevent pasting.
+ clearTimeout(searchTimeout);
+ // zero-timeout necessary here because at the time of event handler execution the
+ // pasted content is not in the input field yet. Shouldn’t make any difference for
+ // change, though.
+ setTimeout(search, 0);
});
// Push and pop states are used to add search results to the browser
/*globals $: true, rootPath: true */
document.addEventListener('DOMContentLoaded', function() {
+ 'use strict';
+
if (!window.playgroundUrl) {
return;
}
}
var a = document.createElement('a');
- a.textContent = '⇱';
a.setAttribute('class', 'test-arrow');
+ a.textContent = 'Run';
var code = el.previousElementSibling.textContent;
/// strictly increasing (i.e. chain[0].level < chain[1].level <
/// ...) with each entry being the most recent occurrence of a
/// heading with that level (it doesn't include the most recent
- /// occurrences of every level, just, if *is* in `chain` then is is
- /// the most recent one).
+ /// occurrences of every level, just, if it *is* in `chain` then
+ /// it is the most recent one).
///
/// We also have `chain[0].level <= top_level.entries[last]`.
chain: Vec<TocEntry>
#![feature(box_syntax)]
#![feature(dynamic_lib)]
#![feature(libc)]
-#![feature(path_ext)]
#![feature(path_relative_from)]
#![feature(rustc_private)]
#![feature(set_stdio)]
for &(name, _, description) in PASSES {
println!("{:>20} - {}", name, description);
}
- println!("{}", "\nDefault passes for rustdoc:"); // FIXME: #9970
+ println!("\nDefault passes for rustdoc:");
for &name in DEFAULT_PASSES {
println!("{:>20}", name);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use std::collections::HashSet;
-use rustc::util::nodemap::NodeSet;
+use rustc::util::nodemap::DefIdSet;
use std::cmp;
use std::string::String;
use std::usize;
-use syntax::ast;
use rustc_front::hir;
use clean;
/// Strip items marked `#[doc(hidden)]`
pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
- let mut stripped = HashSet::new();
+ let mut stripped = DefIdSet();
// strip all #[doc(hidden)] items
let krate = {
struct Stripper<'a> {
- stripped: &'a mut HashSet<ast::NodeId>
- };
+ stripped: &'a mut DefIdSet
+ }
impl<'a> fold::DocFolder for Stripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if i.is_hidden_from_doc() {
debug!("found one in strip_hidden; removing");
- self.stripped.insert(i.def_id.node);
+ self.stripped.insert(i.def_id);
// use a dedicated hidden item for given item type if any
match i.inner {
// strip any traits implemented on stripped items
let krate = {
struct ImplStripper<'a> {
- stripped: &'a mut HashSet<ast::NodeId>
- };
+ stripped: &'a mut DefIdSet
+ }
impl<'a> fold::DocFolder for ImplStripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if let clean::ImplItem(clean::Impl{
ref trait_, ..
}) = i.inner {
// Impls for stripped types don't need to exist
- if self.stripped.contains(&did.node) {
+ if self.stripped.contains(&did) {
return None;
}
// Impls of stripped traits also don't need to exist
if let Some(clean::ResolvedPath { did, .. }) = *trait_ {
- if self.stripped.contains(&did.node) {
+ if self.stripped.contains(&did) {
return None;
}
}
/// crate, specified by the `xcrate` flag.
pub fn strip_private(mut krate: clean::Crate) -> plugins::PluginResult {
// This stripper collects all *retained* nodes.
- let mut retained = HashSet::new();
+ let mut retained = DefIdSet();
let analysis = super::ANALYSISKEY.with(|a| a.clone());
let analysis = analysis.borrow();
let analysis = analysis.as_ref().unwrap();
}
struct Stripper<'a> {
- retained: &'a mut HashSet<ast::NodeId>,
- exported_items: &'a NodeSet,
+ retained: &'a mut DefIdSet,
+ exported_items: &'a DefIdSet,
}
impl<'a> fold::DocFolder for Stripper<'a> {
clean::VariantItem(..) | clean::MethodItem(..) |
clean::ForeignFunctionItem(..) | clean::ForeignStaticItem(..) => {
if i.def_id.is_local() {
- if !self.exported_items.contains(&i.def_id.node) {
+ if !self.exported_items.contains(&i.def_id) {
return None;
}
// Traits are in exported_items even when they're totally private.
}
clean::ConstantItem(..) => {
- if i.def_id.is_local() &&
- !self.exported_items.contains(&i.def_id.node) {
+ if i.def_id.is_local() && !self.exported_items.contains(&i.def_id) {
return None;
}
}
clean::ImplItem(clean::Impl{
for_: clean::ResolvedPath{ did, .. }, ..
}) => {
- if did.is_local() &&
- !self.exported_items.contains(&did.node) {
+ if did.is_local() && !self.exported_items.contains(&did) {
return None;
}
}
};
let i = if fastreturn {
- self.retained.insert(i.def_id.node);
+ self.retained.insert(i.def_id);
return Some(i);
} else {
self.fold_item_recur(i)
i.doc_value().is_none() => None,
clean::ImplItem(ref i) if i.items.is_empty() => None,
_ => {
- self.retained.insert(i.def_id.node);
+ self.retained.insert(i.def_id);
Some(i)
}
}
}
// This stripper discards all private impls of traits
-struct ImplStripper<'a>(&'a HashSet<ast::NodeId>);
+struct ImplStripper<'a>(&'a DefIdSet);
impl<'a> fold::DocFolder for ImplStripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if let clean::ImplItem(ref imp) = i.inner {
match imp.trait_ {
Some(clean::ResolvedPath{ did, .. }) => {
- let ImplStripper(s) = *self;
- if did.is_local() && !s.contains(&did.node) {
+ if did.is_local() && !self.0.contains(&did) {
return None;
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(deprecated)]
+
use clean;
use std::dynamic_lib as dl;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(deprecated)]
+
use std::cell::{RefCell, Cell};
use std::collections::{HashSet, HashMap};
use std::dynamic_lib::DynamicLibrary;
use testing;
use rustc_lint;
+use rustc::front::map as hir_map;
use rustc::session::{self, config};
-use rustc::session::config::get_unstable_features_setting;
+use rustc::session::config::{get_unstable_features_setting, OutputType};
use rustc::session::search_paths::{SearchPaths, PathKind};
-use rustc_front::lowering::lower_crate;
+use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_back::tempdir::TempDir;
use rustc_driver::{driver, Compilation};
use syntax::codemap::CodeMap;
"rustdoc-test", None)
.expect("phase_2_configure_and_expand aborted in rustdoc!");
let krate = driver::assign_node_ids(&sess, krate);
- let krate = lower_crate(&krate);
+ let lcx = LoweringContext::new(&sess, Some(&krate));
+ let krate = lower_crate(&lcx, &krate);
let opts = scrape_test_config(&krate);
+ let mut forest = hir_map::Forest::new(krate);
+ let map = hir_map::map_crate(&mut forest);
+
let ctx = core::DocContext {
- krate: &krate,
- maybe_typed: core::NotTyped(sess),
+ map: &map,
+ maybe_typed: core::NotTyped(&sess),
input: input,
external_paths: RefCell::new(Some(HashMap::new())),
external_traits: RefCell::new(None),
};
let mut v = RustdocVisitor::new(&ctx, None);
- v.visit(ctx.krate);
+ v.visit(ctx.map.krate());
let mut krate = v.clean(&ctx);
match crate_name {
Some(name) => krate.name = name,
// Look for #![doc(test(no_crate_inject))], used by crates in the std facade
fn scrape_test_config(krate: &::rustc_front::hir::Crate) -> TestOptions {
- use rustc_front::attr::AttrMetaMethods;
- use rustc_front::print::pprust;
+ use syntax::attr::AttrMetaMethods;
+ use syntax::print::pprust;
let mut opts = TestOptions {
no_crate_inject: false,
// never wrap the test in `fn main() { ... }`
let test = maketest(test, Some(cratename), as_test_harness, opts);
let input = config::Input::Str(test.to_string());
+ let mut outputs = HashMap::new();
+ outputs.insert(OutputType::Exe, None);
let sessopts = config::Options {
maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap()
.parent().unwrap().to_path_buf()),
search_paths: libs,
crate_types: vec!(config::CrateTypeExecutable),
- output_types: vec!(config::OutputTypeExe),
+ output_types: outputs,
externs: externs,
cg: config::CodegenOptions {
prefer_dynamic: true,
use syntax::abi;
use syntax::ast;
+use syntax::attr;
+use syntax::attr::AttrMetaMethods;
use syntax::codemap::Span;
use rustc::front::map as hir_map;
-use rustc::middle::def_id::DefId;
use rustc::middle::stability;
-use rustc_front::attr;
-use rustc_front::attr::AttrMetaMethods;
use rustc_front::hir;
use core;
pub struct RustdocVisitor<'a, 'tcx: 'a> {
pub module: Module,
- pub attrs: Vec<hir::Attribute>,
+ pub attrs: Vec<ast::Attribute>,
pub cx: &'a core::DocContext<'a, 'tcx>,
pub analysis: Option<&'a core::CrateAnalysis>,
view_item_stack: HashSet<ast::NodeId>,
}
fn stability(&self, id: ast::NodeId) -> Option<attr::Stability> {
- self.cx.tcx_opt().and_then(
- |tcx| stability::lookup(tcx, DefId::local(id)).map(|x| x.clone()))
+ self.cx.tcx_opt().and_then(|tcx| {
+ self.cx.map.opt_local_def_id(id)
+ .and_then(|def_id| stability::lookup(tcx, def_id))
+ .cloned()
+ })
}
pub fn visit(&mut self, krate: &hir::Crate) {
self.module.is_crate = true;
}
- pub fn visit_struct_def(&mut self, item: &hir::Item,
- name: ast::Ident, sd: &hir::StructDef,
+ pub fn visit_variant_data(&mut self, item: &hir::Item,
+ name: ast::Name, sd: &hir::VariantData,
generics: &hir::Generics) -> Struct {
debug!("Visiting struct");
let struct_type = struct_type_from_def(&*sd);
stab: self.stability(item.id),
attrs: item.attrs.clone(),
generics: generics.clone(),
- fields: sd.fields.clone(),
+ fields: sd.fields().iter().cloned().collect(),
whence: item.span
}
}
pub fn visit_enum_def(&mut self, it: &hir::Item,
- name: ast::Ident, def: &hir::EnumDef,
+ name: ast::Name, def: &hir::EnumDef,
params: &hir::Generics) -> Enum {
debug!("Visiting enum");
Enum {
variants: def.variants.iter().map(|v| Variant {
name: v.node.name,
attrs: v.node.attrs.clone(),
- vis: v.node.vis,
- stab: self.stability(v.node.id),
- id: v.node.id,
- kind: v.node.kind.clone(),
+ stab: self.stability(v.node.data.id()),
+ def: v.node.data.clone(),
whence: v.span,
}).collect(),
vis: it.vis,
}
pub fn visit_fn(&mut self, item: &hir::Item,
- name: ast::Ident, fd: &hir::FnDecl,
+ name: ast::Name, fd: &hir::FnDecl,
unsafety: &hir::Unsafety,
constness: hir::Constness,
abi: &abi::Abi,
}
}
- pub fn visit_mod_contents(&mut self, span: Span, attrs: Vec<hir::Attribute> ,
+ pub fn visit_mod_contents(&mut self, span: Span, attrs: Vec<ast::Attribute> ,
vis: hir::Visibility, id: ast::NodeId,
m: &hir::Mod,
- name: Option<ast::Ident>) -> Module {
+ name: Option<ast::Name>) -> Module {
let mut om = Module::new(name);
om.where_outer = span;
om.where_inner = m.inner;
}
- fn resolve_id(&mut self, id: ast::NodeId, renamed: Option<ast::Ident>,
+ fn resolve_id(&mut self, id: ast::NodeId, renamed: Option<ast::Name>,
glob: bool, om: &mut Module, please_inline: bool) -> bool {
let tcx = match self.cx.tcx_opt() {
Some(tcx) => tcx,
None => return false
};
let def = tcx.def_map.borrow()[&id].def_id();
- if !def.is_local() { return false }
+ let def_node_id = match tcx.map.as_local_node_id(def) {
+ Some(n) => n, None => return false
+ };
let analysis = match self.analysis {
Some(analysis) => analysis, None => return false
};
- if !please_inline && analysis.public_items.contains(&def.node) {
+ if !please_inline && analysis.public_items.contains(&def) {
return false
}
- if !self.view_item_stack.insert(def.node) { return false }
+ if !self.view_item_stack.insert(def_node_id) { return false }
- let ret = match tcx.map.get(def.node) {
+ let ret = match tcx.map.get(def_node_id) {
hir_map::NodeItem(it) => {
if glob {
let prev = mem::replace(&mut self.inlining_from_glob, true);
}
_ => false,
};
- self.view_item_stack.remove(&id);
+ self.view_item_stack.remove(&def_node_id);
return ret;
}
pub fn visit_item(&mut self, item: &hir::Item,
- renamed: Option<ast::Ident>, om: &mut Module) {
+ renamed: Option<ast::Name>, om: &mut Module) {
debug!("Visiting item {:?}", item);
- let name = renamed.unwrap_or(item.ident);
+ let name = renamed.unwrap_or(item.name);
match item.node {
hir::ItemExternCrate(ref p) => {
let path = match *p {
hir::ItemEnum(ref ed, ref gen) =>
om.enums.push(self.visit_enum_def(item, name, ed, gen)),
hir::ItemStruct(ref sd, ref gen) =>
- om.structs.push(self.visit_struct_def(item, name, &**sd, gen)),
+ om.structs.push(self.visit_variant_data(item, name, sd, gen)),
hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
constness, abi, gen)),
Macro {
id: def.id,
attrs: def.attrs.clone(),
- name: def.ident,
+ name: def.name,
whence: def.span,
stab: self.stability(def.id),
imported_from: def.imported_from,
//! Create a struct called `TestStruct` and serialize and deserialize it to and from JSON using the
//! serialization API, using the derived serialization code.
//!
-//! ```notrust
-//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment
+//! ```rust
//! extern crate serialize;
//! use serialize::json;
//!
//!
//! ### Simple example of `ToJson` usage
//!
-//! ```notrust
-//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment
+//! ```rust
//! extern crate serialize;
//! use serialize::json::{self, ToJson, Json};
//!
//!
//! ### Verbose example of `ToJson` usage
//!
-//! ```notrust
-//! // FIXME(#19470): this cannot be ```rust``` because it fails orphan checking at the moment
+//! ```rust
//! extern crate serialize;
//! use std::collections::BTreeMap;
//! use serialize::json::{self, Json, ToJson};
/// The hashes are all keyed by the thread-local random number generator
/// on creation by default. This means that the ordering of the keys is
/// randomized, but makes the tables more resistant to
-/// denial-of-service attacks (Hash DoS). This behaviour can be
+/// denial-of-service attacks (Hash DoS). This behavior can be
/// overridden with one of the constructors.
///
/// It is required that the keys implement the `Eq` and `Hash` traits, although
F: FnMut(&K) -> bool,
{
// This is the only function where capacity can be zero. To avoid
- // undefined behaviour when Bucket::new gets the raw bucket in this
+ // undefined behavior when Bucket::new gets the raw bucket in this
// case, immediately return the appropriate search result.
if table.capacity() == 0 {
return TableRef(table);
self.search_mut(k).map(|bucket| bucket.into_mut_refs().1)
}
- /// Inserts a key-value pair into the map. If the key already had a value
- /// present in the map, that value is returned. Otherwise, `None` is returned.
+ /// Inserts a key-value pair into the map.
+ ///
+ /// If the map did not have this key present, `None` is returned.
+ ///
+ /// If the map did have this key present, that value is returned, and the
+ /// entry is not updated. See the [module-level documentation] for more.
+ ///
+ /// [module-level documentation]: index.html#insert-and-complex-keys
///
/// # Examples
///
other.is_subset(self)
}
- /// Adds a value to the set. Returns `true` if the value was not already
- /// present in the set.
+ /// Adds a value to the set.
+ ///
+ /// If the set did not have a value present, `true` is returned.
+ ///
+ /// If the set did have this key present, that value is returned, and the
+ /// entry is not updated. See the [module-level documentation] for more.
+ ///
+ /// [module-level documentation]: index.html#insert-and-complex-keys
///
/// # Examples
///
impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
fn drop(&mut self) {
- for _ in self.by_ref() {}
+ for _ in self {}
}
}
}
impl<K, V> Drop for RawTable<K, V> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
if self.capacity == 0 || self.capacity == mem::POST_DROP_USIZE {
return;
//! ```
//! use std::collections::btree_map::BTreeMap;
//!
-//! // A client of the bar. They have an id and a blood alcohol level.
-//! struct Person { id: u32, blood_alcohol: f32 }
+//! // A client of the bar. They have a blood alcohol level.
+//! struct Person { blood_alcohol: f32 }
//!
//! // All the orders made to the bar, by client id.
//! let orders = vec![1,2,1,2,3,4,1,2,2,3,4,1,1,1];
//! for id in orders {
//! // If this is the first time we've seen this customer, initialize them
//! // with no blood alcohol. Otherwise, just retrieve them.
-//! let person = blood_alcohol.entry(id).or_insert(Person{id: id, blood_alcohol: 0.0});
+//! let person = blood_alcohol.entry(id).or_insert(Person { blood_alcohol: 0.0 });
//!
//! // Reduce their blood alcohol level. It takes time to order and drink a beer!
//! person.blood_alcohol *= 0.9;
//! // Check if they're sober enough to have another beer.
//! if person.blood_alcohol > 0.3 {
//! // Too drunk... for now.
-//! println!("Sorry {}, I have to cut you off", person.id);
+//! println!("Sorry {}, I have to cut you off", id);
//! } else {
//! // Have another!
//! person.blood_alcohol += 0.1;
//! }
//! }
//! ```
+//!
+//! # Insert and complex keys
+//!
+//! If we have a more complex key, calls to `insert()` will
+//! not update the value of the key. For example:
+//!
+//! ```
+//! use std::cmp::Ordering;
+//! use std::collections::BTreeMap;
+//! use std::hash::{Hash, Hasher};
+//!
+//! #[derive(Debug)]
+//! struct Foo {
+//! a: u32,
+//! b: &'static str,
+//! }
+//!
+//! // we will compare `Foo`s by their `a` value only.
+//! impl PartialEq for Foo {
+//! fn eq(&self, other: &Self) -> bool { self.a == other.a }
+//! }
+//!
+//! impl Eq for Foo {}
+//!
+//! // we will hash `Foo`s by their `a` value only.
+//! impl Hash for Foo {
+//! fn hash<H: Hasher>(&self, h: &mut H) { self.a.hash(h); }
+//! }
+//!
+//! impl PartialOrd for Foo {
+//! fn partial_cmp(&self, other: &Self) -> Option<Ordering> { self.a.partial_cmp(&other.a) }
+//! }
+//!
+//! impl Ord for Foo {
+//! fn cmp(&self, other: &Self) -> Ordering { self.a.cmp(&other.a) }
+//! }
+//!
+//! let mut map = BTreeMap::new();
+//! map.insert(Foo { a: 1, b: "baz" }, ());
+//!
+//! // We already have a Foo with an a of 1, so this will be updating the value.
+//! map.insert(Foo { a: 1, b: "xyz" }, ());
+//!
+//! // ... but the key hasn't changed. b is still "baz", not "xyz"
+//! assert_eq!(map.keys().next().unwrap().b, "baz");
+//! ```
#![stable(feature = "rust1", since = "1.0.0")]
reason = "API has not been scrutinized and is highly likely to \
either disappear or change",
issue = "27810")]
+#![deprecated(since = "1.5.0", reason = "replaced with crates.io crates")]
#![allow(missing_docs)]
+#![allow(deprecated)]
use prelude::v1::*;
use env;
use ffi::{CString, OsString};
-use mem;
use path::{Path, PathBuf};
pub struct DynamicLibrary {
// the destructor does not run.
match maybe_symbol_value {
Err(err) => Err(err),
- Ok(symbol_value) => Ok(mem::transmute(symbol_value))
+ Ok(symbol_value) => Ok(symbol_value as *mut T)
}
}
}
/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
///
+/// # Panics
+///
+/// This function may panic if `key` is empty, contains an ASCII equals sign
+/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
+/// character.
+///
/// # Examples
///
/// ```
/// - [Austin Group Bugzilla](http://austingroupbugs.net/view.php?id=188)
/// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2)
///
+/// # Panics
+///
+/// This function may panic if `key` is empty, contains an ASCII equals sign
+/// `'='` or the NUL character `'\0'`, or when the value contains the NUL
+/// character.
+///
/// # Examples
///
/// ```
/// Returns the value of the 'HOME' environment variable if it is
/// set and not equal to the empty string. Otherwise, returns the value of the
/// 'USERPROFILE' environment variable if it is set and not equal to the empty
-/// string.
+/// string. If both do not exist, [`GetUserProfileDirectory`][msdn] is used to
+/// return the appropriate path.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/bb762280(v=vs.85).aspx
///
/// # Examples
///
///
/// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
/// 'USERPROFILE' environment variable if any are set and not the empty
-/// string. Otherwise, tmpdir returns the path to the Windows directory.
+/// string. Otherwise, tmpdir returns the path to the Windows directory. This
+/// behavior is identical to that of [GetTempPath][msdn], which this function
+/// uses internally.
+///
+/// [msdn]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992(v=vs.85).aspx
///
/// ```
/// use std::env;
use option::Option::{self, Some, None};
use result::Result::{self, Ok, Err};
use slice;
-use str;
+use str::{self, Utf8Error};
use string::String;
use vec::Vec;
#[stable(feature = "rust1", since = "1.0.0")]
pub struct NulError(usize, Vec<u8>);
+/// An error returned from `CString::into_string` to indicate that a UTF-8 error
+/// was encountered during the conversion.
+#[derive(Clone, PartialEq, Debug)]
+#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+pub struct IntoStringError {
+ inner: CString,
+ error: Utf8Error,
+}
+
impl CString {
/// Creates a new C-compatible string from a container of bytes.
///
/// Retakes ownership of a CString that was transferred to C.
///
/// The only appropriate argument is a pointer obtained by calling
- /// `into_ptr`. The length of the string will be recalculated
+ /// `into_raw`. The length of the string will be recalculated
/// using the pointer.
#[unstable(feature = "cstr_memory2", reason = "recently added",
issue = "27769")]
/// Transfers ownership of the string to a C caller.
///
/// The pointer must be returned to Rust and reconstituted using
- /// `from_ptr` to be properly deallocated. Specifically, one
+ /// `from_raw` to be properly deallocated. Specifically, one
/// should *not* use the standard C `free` function to deallocate
/// this string.
///
- /// Failure to call `from_ptr` will lead to a memory leak.
+ /// Failure to call `from_raw` will lead to a memory leak.
#[stable(feature = "cstr_memory", since = "1.4.0")]
pub fn into_raw(self) -> *mut libc::c_char {
Box::into_raw(self.inner) as *mut libc::c_char
}
+ /// Converts the `CString` into a `String` if it contains valid Unicode data.
+ ///
+ /// On failure, ownership of the original `CString` is returned.
+ #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+ pub fn into_string(self) -> Result<String, IntoStringError> {
+ String::from_utf8(self.into_bytes())
+ .map_err(|e| IntoStringError {
+ error: e.utf8_error(),
+ inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) },
+ })
+ }
+
+ /// Returns the underlying byte buffer.
+ ///
+ /// The returned buffer does **not** contain the trailing nul separator and
+ /// it is guaranteed to not have any interior nul bytes.
+ #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+ pub fn into_bytes(self) -> Vec<u8> {
+ // FIXME: Once this method becomes stable, add an `impl Into<Vec<u8>> for CString`
+ let mut vec = self.inner.into_vec();
+ let _nul = vec.pop();
+ debug_assert_eq!(_nul, Some(0u8));
+ vec
+ }
+
+ /// Equivalent to the `into_bytes` function except that the returned vector
+ /// includes the trailing nul byte.
+ #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+ pub fn into_bytes_with_nul(self) -> Vec<u8> {
+ self.inner.into_vec()
+ }
+
/// Returns the contents of this `CString` as a slice of bytes.
///
/// The returned slice does **not** contain the trailing nul separator and
}
}
+impl IntoStringError {
+ /// Consumes this error, returning original `CString` which generated the
+ /// error.
+ #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+ pub fn into_cstring(self) -> CString {
+ self.inner
+ }
+
+ /// Access the underlying UTF-8 error that was the cause of this error.
+ #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+ pub fn utf8_error(&self) -> Utf8Error {
+ self.error
+ }
+}
+
+#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+impl Error for IntoStringError {
+ fn description(&self) -> &str {
+ Error::description(&self.error)
+ }
+}
+
+#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")]
+impl fmt::Display for IntoStringError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.error, f)
+ }
+}
+
impl CStr {
/// Casts a raw C string to a safe C string wrapper.
///
#![stable(feature = "rust1", since = "1.0.0")]
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::c_str::{CString, CStr, NulError};
+pub use self::c_str::{CString, CStr, NulError, IntoStringError};
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::os_str::{OsString, OsStr};
/// represents known metadata about a file such as its permissions, size,
/// modification times, etc.
#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Clone)]
pub struct Metadata(fs_imp::FileAttr);
/// Iterator over the entries in a directory.
/// Returns the canonical form of a path with all intermediate components
/// normalized and symbolic links resolved.
-#[unstable(feature = "fs_canonicalize", reason = "recently added API",
- issue = "27706")]
+///
+/// This function may return an error in situations like where the path does not
+/// exist, a component in the path is not a directory, or an I/O error happens.
+///
+/// # Examples
+///
+/// ```
+/// use std::fs;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let path = try!(fs::canonicalize("../a/../foo.txt"));
+/// # Ok(())
+/// # }
+/// ```
+#[stable(feature = "fs_canonicalize", since = "1.5.0")]
pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
fs_imp::canonicalize(path.as_ref())
}
}
/// Utility methods for paths.
-#[unstable(feature = "path_ext",
+#[unstable(feature = "path_ext_deprecated",
reason = "The precise set of methods exposed on this trait may \
change and some methods may be removed. For stable code, \
see the std::fs::metadata function.",
issue = "27725")]
+#[deprecated(since = "1.5.0", reason = "replaced with inherent methods")]
pub trait PathExt {
/// Gets information on the file, directory, etc at this path.
///
fn is_dir(&self) -> bool;
}
+#[allow(deprecated)]
impl PathExt for Path {
fn metadata(&self) -> io::Result<Metadata> { metadata(self) }
fn symlink_metadata(&self) -> io::Result<Metadata> { symlink_metadata(self) }
check!(fs::create_dir_all(&path.join("a/")));
}
+ #[test]
+ fn canonicalize_works_simple() {
+ let tmpdir = tmpdir();
+ let tmpdir = fs::canonicalize(tmpdir.path()).unwrap();
+ let file = tmpdir.join("test");
+ File::create(&file).unwrap();
+ assert_eq!(fs::canonicalize(&file).unwrap(), file);
+ }
+
#[test]
#[cfg(not(windows))]
fn realpath_works() {
}
}
}
+
+ #[test]
+ fn read_dir_not_found() {
+ let res = fs::read_dir("/path/that/does/not/exist");
+ assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound);
+ }
}
/// let stream = match stream.into_inner() {
/// Ok(s) => s,
/// Err(e) => {
- /// // Here, e is a IntoInnerError, let's re-examine the buffer:
+ /// // Here, e is an IntoInnerError, let's re-examine the buffer:
/// let buffer = e.into_inner();
///
/// // do stuff to try to recover
/// use std::io::Cursor;
/// let mut buff = Cursor::new(vec![0; 15]);
///
-/// write_ten_bytes(&mut buff).unwrap();
+/// write_ten_bytes_at_end(&mut buff).unwrap();
///
/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
/// }
pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
}
-macro_rules! seek {
- () => {
- fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
- let pos = match style {
- SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
- SeekFrom::End(n) => self.inner.len() as i64 + n,
- SeekFrom::Current(n) => self.pos as i64 + n,
- };
-
- if pos < 0 {
- Err(Error::new(ErrorKind::InvalidInput,
- "invalid seek to a negative position"))
- } else {
- self.pos = pos as u64;
- Ok(self.pos)
- }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]> {
+ fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
+ let pos = match style {
+ SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
+ SeekFrom::End(n) => self.inner.as_ref().len() as i64 + n,
+ SeekFrom::Current(n) => self.pos as i64 + n,
+ };
+
+ if pos < 0 {
+ Err(Error::new(ErrorKind::InvalidInput,
+ "invalid seek to a negative position"))
+ } else {
+ self.pos = pos as u64;
+ Ok(self.pos)
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> io::Seek for Cursor<&'a [u8]> { seek!(); }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> io::Seek for Cursor<&'a mut [u8]> { seek!(); }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl io::Seek for Cursor<Vec<u8>> { seek!(); }
-
-macro_rules! read {
- () => {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- let n = try!(Read::read(&mut try!(self.fill_buf()), buf));
- self.pos += n as u64;
- Ok(n)
- }
+impl<T> Read for Cursor<T> where T: AsRef<[u8]> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let n = try!(Read::read(&mut try!(self.fill_buf()), buf));
+ self.pos += n as u64;
+ Ok(n)
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Read for Cursor<&'a [u8]> { read!(); }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> Read for Cursor<&'a mut [u8]> { read!(); }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Read for Cursor<Vec<u8>> { read!(); }
-
-macro_rules! buffer {
- () => {
- fn fill_buf(&mut self) -> io::Result<&[u8]> {
- let amt = cmp::min(self.pos, self.inner.len() as u64);
- Ok(&self.inner[(amt as usize)..])
- }
- fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
+impl<T> BufRead for Cursor<T> where T: AsRef<[u8]> {
+ fn fill_buf(&mut self) -> io::Result<&[u8]> {
+ let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
+ Ok(&self.inner.as_ref()[(amt as usize)..])
}
+ fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> BufRead for Cursor<&'a [u8]> { buffer!(); }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> BufRead for Cursor<&'a mut [u8]> { buffer!(); }
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a> BufRead for Cursor<Vec<u8>> { buffer!(); }
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for Cursor<&'a mut [u8]> {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
+#[stable(feature = "cursor_box_slice", since = "1.5.0")]
+impl Write for Cursor<Box<[u8]>> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ let pos = cmp::min(self.pos, self.inner.len() as u64);
+ let amt = try!((&mut self.inner[(pos as usize)..]).write(buf));
+ self.pos += amt as u64;
+ Ok(amt)
+ }
+ fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
#[cfg(test)]
mod tests {
assert_eq!(&writer.get_ref()[..], b);
}
+ #[test]
+ fn test_box_slice_writer() {
+ let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
+ assert_eq!(writer.position(), 0);
+ assert_eq!(writer.write(&[0]).unwrap(), 1);
+ assert_eq!(writer.position(), 1);
+ assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
+ assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
+ assert_eq!(writer.position(), 8);
+ assert_eq!(writer.write(&[]).unwrap(), 0);
+ assert_eq!(writer.position(), 8);
+
+ assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
+ assert_eq!(writer.write(&[10]).unwrap(), 0);
+ let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+ assert_eq!(&**writer.get_ref(), b);
+ }
+
#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
assert_eq!(reader.read(&mut buf).unwrap(), 0);
}
+ #[test]
+ fn test_boxed_slice_reader() {
+ let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7).into_boxed_slice());
+ let mut buf = [];
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ assert_eq!(reader.position(), 0);
+ let mut buf = [0];
+ assert_eq!(reader.read(&mut buf).unwrap(), 1);
+ assert_eq!(reader.position(), 1);
+ let b: &[_] = &[0];
+ assert_eq!(buf, b);
+ let mut buf = [0; 4];
+ assert_eq!(reader.read(&mut buf).unwrap(), 4);
+ assert_eq!(reader.position(), 5);
+ let b: &[_] = &[1, 2, 3, 4];
+ assert_eq!(buf, b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 3);
+ let b: &[_] = &[5, 6, 7];
+ assert_eq!(&buf[..3], b);
+ assert_eq!(reader.read(&mut buf).unwrap(), 0);
+ }
+
#[test]
fn read_to_end() {
let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
let mut r = Cursor::new(&mut buf[..]);
assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
assert_eq!(r.write(&[3]).unwrap(), 0);
+
+ let mut r = Cursor::new(vec![10].into_boxed_slice());
+ assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10);
+ assert_eq!(r.write(&[3]).unwrap(), 0);
}
#[test]
let mut buf = [0];
let mut r = Cursor::new(&mut buf[..]);
assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+ let mut r = Cursor::new(vec!(10).into_boxed_slice());
+ assert!(r.seek(SeekFrom::End(-2)).is_err());
}
#[test]
use result;
use sys;
-/// A specialized [`Result`][result] type for I/O operations.
-///
-/// [result]: ../result/enum.Result.html
+/// A specialized [`Result`](../result/enum.Result.html) type for I/O
+/// operations.
///
/// This type is broadly used across `std::io` for any operation which may
/// produce an error.
b.iter(|| {
let mut rd = &buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
b.iter(|| {
let mut wr = &mut buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
b.iter(|| {
let mut rd = &buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = rd.read(&mut dst);
test::black_box(&dst);
}
b.iter(|| {
let mut wr = &mut buf[..];
- for _ in (0 .. 8) {
+ for _ in 0..8 {
let _ = wr.write_all(&src);
test::black_box(&wr);
}
//!
//! # Read and Write
//!
-//! Because they are traits, they're implemented by a number of other types,
-//! and you can implement them for your types too. As such, you'll see a
-//! few different types of I/O throughout the documentation in this module:
-//! `File`s, `TcpStream`s, and somtimes even `Vec<T>`s. For example, `Read`
-//! adds a `read()` method, which we can use on `File`s:
+//! Because they are traits, `Read` and `Write` are implemented by a number
+//! of other types, and you can implement them for your types too. As such,
+//! you'll see a few different types of I/O throughout the documentation in
+//! this module: `File`s, `TcpStream`s, and sometimes even `Vec<T>`s. For
+//! example, `Read` adds a `read()` method, which we can use on `File`s:
//!
//! ```
//! use std::io;
//! # }
//! ```
//!
-//! `BufWriter` doesn't add any new ways of writing, it just buffers every call
+//! `BufWriter` doesn't add any new ways of writing; it just buffers every call
//! to [`write()`][write]:
//!
//! ```
//! # }
//! ```
//!
-//! Of course, using `io::stdout()` directly is less comon than something like
+//! Of course, using `io::stdout()` directly is less common than something like
//! `println!`.
//!
//! ## Iterator types
//! The return type of `read_input()`, `io::Result<()>`, is a very common type
//! for functions which don't have a 'real' return value, but do want to return
//! errors if they happen. In this case, the only purpose of this function is
-//! to read the line and print it, so we use use `()`.
+//! to read the line and print it, so we use `()`.
//!
//! [result]: type.Result.html
//! [try]: macro.try!.html
/// throughout `std::io` take and provide types which implement the `Read`
/// trait.
///
+/// Please note that each call to `read` may involve a system call, and
+/// therefore, using something that implements [`BufRead`][bufread], such as
+/// [`BufReader`][bufreader], will be more efficient.
+///
+/// [bufread]: trait.BufRead.html
+/// [bufreader]: struct.BufReader.html
+///
/// # Examples
///
/// [`File`][file]s implement `Read`:
#![stable(feature = "rust1", since = "1.0.0")]
pub use super::{Read, Write, BufRead, Seek};
+#[allow(deprecated)]
pub use fs::PathExt;
inner: Arc<Mutex<BufReader<Maybe<StdinRaw>>>>,
}
-/// A locked reference to the a `Stdin` handle.
+/// A locked reference to the `Stdin` handle.
///
/// This handle implements both the `Read` and `BufRead` traits and is
/// constructed via the `lock` method on `Stdin`.
inner: Arc<ReentrantMutex<RefCell<LineWriter<Maybe<StdoutRaw>>>>>,
}
-/// A locked reference to the a `Stdout` handle.
+/// A locked reference to the `Stdout` handle.
///
/// This handle implements the `Write` trait and is constructed via the `lock`
/// method on `Stdout`.
inner: Arc<ReentrantMutex<RefCell<Maybe<StderrRaw>>>>,
}
-/// A locked reference to the a `Stderr` handle.
+/// A locked reference to the `Stderr` handle.
///
/// This handle implements the `Write` trait and is constructed via the `lock`
/// method on `Stderr`.
//! language primitives](#primitives), [standard macros](#macros),
//! [I/O](io/index.html) and [multithreading](thread/index.html), among
//! [many other
-//! things](#what-is-in-the-standard-library-documentation?).
+//! things](#what-is-in-the-standard-library-documentation).
//!
//! `std` is available to all Rust crates by default, just as if each
//! one contained an `extern crate std` import at the [crate
//! not.
//!
//! Slices can only be handled through some kind of *pointer*, and as
-//! such come in many flavours such as:
+//! such come in many flavors such as:
//!
//! * `&[T]` - *shared slice*
//! * `&mut [T]` - *mutable slice*
test(no_crate_inject, attr(deny(warnings))),
test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))]
+// SNAP 1af31d4
+#![allow(unused_features)]
+// SNAP 1af31d4
+#![allow(unused_attributes)]
+
#![feature(alloc)]
#![feature(allow_internal_unstable)]
#![feature(associated_consts)]
#![feature(borrow_state)]
#![feature(box_syntax)]
-#![feature(char_from_unchecked)]
+#![feature(cfg_target_vendor)]
#![feature(char_internals)]
#![feature(clone_from_slice)]
#![feature(collections)]
#![feature(heap_api)]
#![feature(int_error_internals)]
#![feature(into_cow)]
-#![feature(iter_order)]
#![feature(lang_items)]
#![feature(libc)]
#![feature(linkage, thread_local, asm)]
#![feature(unboxed_closures)]
#![feature(unicode)]
#![feature(unique)]
+#![feature(dropck_parametricity)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(decode_utf16)]
#![feature(unwind_attributes)]
#![feature(vec_push_all)]
-#![feature(vec_resize)]
#![feature(wrapping)]
#![feature(zero_one)]
#![cfg_attr(windows, feature(str_utf16))]
-#![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras, hash_default))]
-#![cfg_attr(test, feature(test, rustc_private, float_consts))]
+#![cfg_attr(test, feature(float_from_str_radix, range_inclusive, float_extras))]
+#![cfg_attr(test, feature(test, rustc_private))]
#![cfg_attr(target_env = "msvc", feature(link_args))]
// Don't link to std. We are std.
/// necessary to use `io::stdout().flush()` to ensure the output is emitted
/// immediately.
///
+/// # Panics
+///
+/// Panics if writing to `io::stdout()` fails.
+///
/// # Examples
///
/// ```
($($arg:tt)*) => ($crate::io::_print(format_args!($($arg)*)));
}
-/// Macro for printing to the standard output.
+/// Macro for printing to the standard output, with a newline.
///
/// Use the `format!` syntax to write data to the standard output.
/// See `std::fmt` for more information.
///
+/// # Panics
+///
+/// Panics if writing to `io::stdout()` fails.
+///
/// # Examples
///
/// ```
use sys_common::{AsInner, FromInner};
use net::{hton, ntoh};
-/// An IP address, either a IPv4 or IPv6 address.
+/// An IP address, either an IPv4 or IPv6 address.
#[unstable(feature = "ip_addr", reason = "recent addition", issue = "27801")]
#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, PartialOrd, Ord)]
pub enum IpAddr {
fn test_from_str_socket_addr() {
assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)),
"77.88.21.11:80".parse());
+ assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)),
+ "77.88.21.11:80".parse());
assert_eq!(Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
"[2a02:6b8:0:1::1]:53".parse());
+ assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1,
+ 0, 0, 0, 1), 53, 0, 0)),
+ "[2a02:6b8:0:1::1]:53".parse());
assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)),
"[::127.0.0.1]:22".parse());
+ assert_eq!(Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0,
+ 0x7F00, 1), 22, 0, 0)),
+ "[::127.0.0.1]:22".parse());
// without port
let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
}
- fn read_socket_addr(&mut self) -> Option<SocketAddr> {
+ fn read_socket_addr_v4(&mut self) -> Option<SocketAddrV4> {
+ let ip_addr = |p: &mut Parser| p.read_ipv4_addr();
+ let colon = |p: &mut Parser| p.read_given_char(':');
+ let port = |p: &mut Parser| {
+ p.read_number(10, 5, 0x10000).map(|n| n as u16)
+ };
+
+ self.read_seq_3(ip_addr, colon, port).map(|t| {
+ let (ip, _, port): (Ipv4Addr, char, u16) = t;
+ SocketAddrV4::new(ip, port)
+ })
+ }
+
+ fn read_socket_addr_v6(&mut self) -> Option<SocketAddrV6> {
let ip_addr = |p: &mut Parser| {
- let ipv4_p = |p: &mut Parser| p.read_ip_addr();
- let ipv6_p = |p: &mut Parser| {
- let open_br = |p: &mut Parser| p.read_given_char('[');
- let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
- let clos_br = |p: &mut Parser| p.read_given_char(']');
- p.read_seq_3::<char, Ipv6Addr, char, _, _, _>(open_br, ip_addr, clos_br)
- .map(|t| match t { (_, ip, _) => IpAddr::V6(ip) })
- };
- p.read_or(&mut [Box::new(ipv4_p), Box::new(ipv6_p)])
+ let open_br = |p: &mut Parser| p.read_given_char('[');
+ let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
+ let clos_br = |p: &mut Parser| p.read_given_char(']');
+ p.read_seq_3(open_br, ip_addr, clos_br).map(|t| t.1)
};
let colon = |p: &mut Parser| p.read_given_char(':');
- let port = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);
+ let port = |p: &mut Parser| {
+ p.read_number(10, 5, 0x10000).map(|n| n as u16)
+ };
- // host, colon, port
self.read_seq_3(ip_addr, colon, port).map(|t| {
- let (ip, _, port): (IpAddr, char, u16) = t;
- match ip {
- IpAddr::V4(ip) => SocketAddr::V4(SocketAddrV4::new(ip, port)),
- IpAddr::V6(ip) => SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)),
- }
+ let (ip, _, port): (Ipv6Addr, char, u16) = t;
+ SocketAddrV6::new(ip, port, 0, 0)
})
}
+
+ fn read_socket_addr(&mut self) -> Option<SocketAddr> {
+ let v4 = |p: &mut Parser| p.read_socket_addr_v4().map(SocketAddr::V4);
+ let v6 = |p: &mut Parser| p.read_socket_addr_v6().map(SocketAddr::V6);
+ self.read_or(&mut [Box::new(v4), Box::new(v6)])
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
}
}
+#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
+impl FromStr for SocketAddrV4 {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddrV4, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v4()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
+#[stable(feature = "socket_addr_from_str", since = "1.5.0")]
+impl FromStr for SocketAddrV6 {
+ type Err = AddrParseError;
+ fn from_str(s: &str) -> Result<SocketAddrV6, AddrParseError> {
+ match Parser::new(s).read_till_eof(|p| p.read_socket_addr_v6()) {
+ Some(s) => Ok(s),
+ None => Err(AddrParseError(())),
+ }
+ }
+}
+
#[stable(feature = "rust1", since = "1.0.0")]
impl FromStr for SocketAddr {
type Err = AddrParseError;
/// to this listener. The port allocated can be queried via the
/// `socket_addr` function.
///
- /// The address type can be any implementer of `ToSocketAddrs` trait. See
+ /// The address type can be any implementor of `ToSocketAddrs` trait. See
/// its documentation for concrete examples.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> {
}
#[test]
- fn connect_ip4_loopback() {
- let addr = next_test_ip4();
- let acceptor = t!(TcpListener::bind(&addr));
-
- let _t = thread::spawn(move|| {
- let mut stream = t!(TcpStream::connect(&("127.0.0.1", addr.port())));
- t!(stream.write(&[44]));
- });
-
- let mut stream = t!(acceptor.accept()).0;
- let mut buf = [0];
- t!(stream.read(&mut buf));
- assert!(buf[0] == 44);
- }
-
- #[test]
- fn connect_ip6_loopback() {
- let addr = next_test_ip6();
- let acceptor = t!(TcpListener::bind(&addr));
+ fn connect_loopback() {
+ each_ip(&mut |addr| {
+ let acceptor = t!(TcpListener::bind(&addr));
- let _t = thread::spawn(move|| {
- let mut stream = t!(TcpStream::connect(&("::1", addr.port())));
- t!(stream.write(&[66]));
- });
+ let _t = thread::spawn(move|| {
+ let host = match addr {
+ SocketAddr::V4(..) => "127.0.0.1",
+ SocketAddr::V6(..) => "::1",
+ };
+ let mut stream = t!(TcpStream::connect(&(host, addr.port())));
+ t!(stream.write(&[66]));
+ });
- let mut stream = t!(acceptor.accept()).0;
- let mut buf = [0];
- t!(stream.read(&mut buf));
- assert!(buf[0] == 66);
+ let mut stream = t!(acceptor.accept()).0;
+ let mut buf = [0];
+ t!(stream.read(&mut buf));
+ assert!(buf[0] == 66);
+ })
}
#[test]
- fn smoke_test_ip6() {
+ fn smoke_test() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
}
#[test]
- fn read_eof_ip4() {
+ fn read_eof() {
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
}
#[test]
- fn multiple_connect_serial_ip4() {
+ fn multiple_connect_serial() {
each_ip(&mut |addr| {
let max = 10;
let acceptor = t!(TcpListener::bind(&addr));
}
#[test]
- fn multiple_connect_interleaved_lazy_schedule_ip4() {
+ fn multiple_connect_interleaved_lazy_schedule() {
const MAX: usize = 10;
each_ip(&mut |addr| {
let acceptor = t!(TcpListener::bind(&addr));
}
#[test]
- fn socket_and_peer_name_ip4() {
+ fn socket_and_peer_name() {
each_ip(&mut |addr| {
let listener = t!(TcpListener::bind(&addr));
let so_name = t!(listener.local_addr());
// it is running in and assigns a port range based on it.
fn base_port() -> u16 {
let cwd = env::current_dir().unwrap();
- let dirs = ["32-opt", "32-nopt", "64-opt", "64-nopt", "64-opt-vg",
+ let dirs = ["32-opt", "32-nopt",
+ "musl-64-opt", "cross-opt",
+ "64-opt", "64-nopt", "64-opt-vg", "64-debug-opt",
"all-opt", "snap3", "dist"];
dirs.iter().enumerate().find(|&(_, dir)| {
cwd.to_str().unwrap().contains(dir)
}
}
- // FIXME #11530 this fails on android because tests are run as root
- #[cfg_attr(any(windows, target_os = "android"), ignore)]
#[test]
fn bind_error() {
- let addr = SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 1);
- match UdpSocket::bind(&addr) {
+ match UdpSocket::bind("1.1.1.1:9999") {
Ok(..) => panic!(),
- Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied),
+ Err(e) => {
+ assert_eq!(e.kind(), ErrorKind::AddrNotAvailable)
+ }
}
}
pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
}
}
-
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = c_long;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i32;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+ #[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! NetBSD/OpenBSD-specific raw type definitions
+//! NetBSD-specific raw type definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u32;
-#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = i32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type fflags_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime: time_t,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
+ pub st_birthtime_nsec: c_long,
+ #[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: off_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: blkcnt_t,
pub st_flags: fflags_t,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gen: u32,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_birthtime: time_t,
- #[stable(feature = "raw_ext", since = "1.1.0")]
- pub st_birthtime_nsec: c_long,
+ st_spare: [u32; 2],
}
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
+#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
use io::prelude::*;
use any::Any;
+use cell::Cell;
use cell::RefCell;
+use intrinsics;
use sys::stdio::Stderr;
use sys_common::backtrace;
use sys_common::thread_info;
-use sys_common::unwind;
+use sys_common::util;
+
+thread_local! { pub static PANIC_COUNT: Cell<usize> = Cell::new(0) }
thread_local! {
pub static LOCAL_STDERR: RefCell<Option<Box<Write + Send>>> = {
}
}
-pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
+fn log_panic(obj: &(Any+Send), file: &'static str, line: u32,
+ log_backtrace: bool) {
let msg = match obj.downcast_ref::<&'static str>() {
Some(s) => *s,
None => match obj.downcast_ref::<String>() {
let mut err = Stderr::new().ok();
let thread = thread_info::current_thread();
let name = thread.as_ref().and_then(|t| t.name()).unwrap_or("<unnamed>");
+
+ let write = |err: &mut ::io::Write| {
+ let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}",
+ name, msg, file, line);
+ if log_backtrace {
+ let _ = backtrace::write(err);
+ }
+ };
+
let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
match (prev, err.as_mut()) {
(Some(mut stderr), _) => {
- // FIXME: what to do when the thread printing panics?
- let _ = writeln!(stderr,
- "thread '{}' panicked at '{}', {}:{}\n",
- name, msg, file, line);
- if backtrace::log_enabled() {
- let _ = backtrace::write(&mut *stderr);
- }
+ write(&mut *stderr);
let mut s = Some(stderr);
LOCAL_STDERR.with(|slot| {
*slot.borrow_mut() = s.take();
});
}
- (None, Some(ref mut err)) => {
- let _ = writeln!(err, "thread '{}' panicked at '{}', {}:{}",
- name, msg, file, line);
- if backtrace::log_enabled() {
- let _ = backtrace::write(err);
- }
- }
+ (None, Some(ref mut err)) => { write(err) }
_ => {}
}
+}
- // If this is a double panic, make sure that we printed a backtrace
- // for this panic.
- match err {
- Some(ref mut err) if unwind::panicking() && !backtrace::log_enabled() => {
- let _ = backtrace::write(err);
- }
- _ => {}
+pub fn on_panic(obj: &(Any+Send), file: &'static str, line: u32) {
+ let panics = PANIC_COUNT.with(|s| {
+ let count = s.get() + 1;
+ s.set(count);
+ count
+ });
+
+ // If this is the third nested call, on_panic triggered the last panic,
+ // otherwise the double-panic check would have aborted the process.
+ // Even if it is likely that on_panic was unable to log the backtrace,
+ // abort immediately to avoid infinite recursion, so that attaching a
+ // debugger provides a useable stacktrace.
+ if panics >= 3 {
+ util::dumb_print(format_args!("thread panicked while processing \
+ panic. aborting."));
+ unsafe { intrinsics::abort() }
+ }
+
+ // If this is a double panic, make sure that we print a backtrace
+ // for this panic. Otherwise only print it if logging is enabled.
+ let log_backtrace = panics >= 2 || backtrace::log_enabled();
+ log_panic(obj, file, line, log_backtrace);
+
+ if panics >= 2 {
+ // If a thread panics while it's already unwinding then we
+ // have limited options. Currently our preference is to
+ // just abort. In the future we may consider resuming
+ // unwinding or otherwise exiting the thread cleanly.
+ util::dumb_print(format_args!("thread panicked while panicking. \
+ aborting."));
+ unsafe { intrinsics::abort() }
}
}
use ascii::*;
use borrow::{Borrow, IntoCow, ToOwned, Cow};
use cmp;
+use fmt;
+use fs;
+use io;
use iter;
use mem;
use ops::{self, Deref};
use string::String;
use vec::Vec;
-use fmt;
use ffi::{OsStr, OsString};
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_separator(c: char) -> bool {
- use ascii::*;
c.is_ascii() && is_sep_byte(c as u8)
}
/// use std::path::Path;
///
/// let path_str = Path::new("foo.txt").to_str();
- //// assert_eq!(path_str, Some("foo.txt"));
+ /// assert_eq!(path_str, Some("foo.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn to_str(&self) -> Option<&str> {
pub fn display(&self) -> Display {
Display { path: self }
}
+
+
+ /// Gets information on the file, directory, etc at this path.
+ ///
+ /// Consult the `fs::metadata` documentation for more info.
+ ///
+ /// This call preserves identical runtime/error semantics with
+ /// `fs::metadata`.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn metadata(&self) -> io::Result<fs::Metadata> {
+ fs::metadata(self)
+ }
+
+ /// Gets information on the file, directory, etc at this path.
+ ///
+ /// Consult the `fs::symlink_metadata` documentation for more info.
+ ///
+ /// This call preserves identical runtime/error semantics with
+ /// `fs::symlink_metadata`.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
+ fs::symlink_metadata(self)
+ }
+
+ /// Returns the canonical form of a path, normalizing all components and
+ /// eliminate all symlinks.
+ ///
+ /// This call preserves identical runtime/error semantics with
+ /// `fs::canonicalize`.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn canonicalize(&self) -> io::Result<PathBuf> {
+ fs::canonicalize(self)
+ }
+
+ /// Reads the symlink at this path.
+ ///
+ /// For more information see `fs::read_link`.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn read_link(&self) -> io::Result<PathBuf> {
+ fs::read_link(self)
+ }
+
+ /// Reads the directory at this path.
+ ///
+ /// For more information see `fs::read_dir`.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
+ fs::read_dir(self)
+ }
+
+ /// Boolean value indicator whether the underlying file exists on the local
+ /// filesystem. Returns false in exactly the cases where `fs::stat` fails.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn exists(&self) -> bool {
+ fs::metadata(self).is_ok()
+ }
+
+ /// Whether the underlying implementation (be it a file path, or something
+ /// else) points at a "regular file" on the FS. Will return false for paths
+ /// to non-existent locations or directories or other non-regular files
+ /// (named pipes, etc). Follows links when making this determination.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn is_file(&self) -> bool {
+ fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
+ }
+
+ /// Whether the underlying implementation (be it a file path, or something
+ /// else) is pointing at a directory in the underlying FS. Will return
+ /// false for paths to non-existent locations or if the item is not a
+ /// directory (eg files, named pipes, etc). Follows links when making this
+ /// determination.
+ #[stable(feature = "path_ext", since = "1.5.0")]
+ pub fn is_dir(&self) -> bool {
+ fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
//! [`Eq`](../cmp/trait.Eq.html),
//! [`Ord`](../cmp/trait.Ord.html)
//! }.
-//! The comparision traits, which implement the comparison operators
+//! The comparison traits, which implement the comparison operators
//! and are often seen in trait bounds.
//! * `std::convert::`{
//! [`AsRef`](../convert/trait.AsRef.html),
//! }.
//! Generic conversions, used by savvy API authors to create
//! overloaded methods.
-//! * `std::default::`[`Default`](../default/trait.Default).
+//! * `std::default::`[`Default`](../default/trait.Default.html).
//! Types that have default values.
//! * `std::iter::`{
//! [`Iterator`](../iter/trait.Iterator.html),
#[doc(primitive = "usize")]
//
-/// The pointer-sized signed integer type.
+/// The pointer-sized unsigned integer type.
///
/// *[See also the `std::usize` module](usize/index.html).*
///
fn into_inner(self) -> imp::Process { self.handle }
}
-/// A handle to a child procesess's stdin
+/// A handle to a child process's stdin
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdin {
inner: AnonPipe
fn into_inner(self) -> AnonPipe { self.inner }
}
-/// A handle to a child procesess's stdout
+/// A handle to a child process's stdout
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStdout {
inner: AnonPipe
fn into_inner(self) -> AnonPipe { self.inner }
}
-/// A handle to a child procesess's stderr
+/// A handle to a child process's stderr
#[stable(feature = "process", since = "1.0.0")]
pub struct ChildStderr {
inner: AnonPipe
fn signal_reported_right() {
use os::unix::process::ExitStatusExt;
- let p = Command::new("/bin/sh").arg("-c").arg("kill -9 $$").spawn();
- assert!(p.is_ok());
- let mut p = p.unwrap();
+ let mut p = Command::new("/bin/sh")
+ .arg("-c").arg("read a")
+ .stdin(Stdio::piped())
+ .spawn().unwrap();
+ p.kill().unwrap();
match p.wait().unwrap().signal() {
Some(9) => {},
- result => panic!("not terminated by signal 9 (instead, {:?})", result),
+ result => panic!("not terminated by signal 9 (instead, {:?})",
+ result),
}
}
/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
-#[unstable(feature = "wait_timeout", reason = "newly added", issue = "27772")]
+#[stable(feature = "wait_timeout", since = "1.5.0")]
pub struct WaitTimeoutResult(bool);
impl WaitTimeoutResult {
/// Returns whether the wait was known to have timed out.
- #[unstable(feature = "wait_timeout", reason = "newly added", issue = "27772")]
+ #[stable(feature = "wait_timeout", since = "1.5.0")]
pub fn timed_out(&self) -> bool {
self.0
}
///
/// Like `wait`, the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
- #[unstable(feature = "wait_timeout", reason = "waiting for Duration",
- issue = "27772")]
+ #[stable(feature = "wait_timeout", since = "1.5.0")]
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
dur: Duration)
-> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)> {
/// use std::sync::mpsc::channel;
/// use std::thread;
///
-/// // tx is is the sending half (tx for transmission), and rx is the receiving
+/// // tx is the sending half (tx for transmission), and rx is the receiving
/// // half (rx for receiving).
/// let (tx, rx) = channel();
///
use cell::UnsafeCell;
use fmt;
use marker;
+use mem;
use ops::{Deref, DerefMut};
+use ptr;
use sys_common::mutex as sys;
use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
pub fn is_poisoned(&self) -> bool {
self.inner.poison.get()
}
+
+ /// Consumes this mutex, returning the underlying data.
+ ///
+ /// # Failure
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return an error instead.
+ #[unstable(feature = "mutex_into_inner", reason = "recently added", issue = "28968")]
+ pub fn into_inner(self) -> LockResult<T> where T: Sized {
+ // We know statically that there are no outstanding references to
+ // `self` so there's no need to lock the inner StaticMutex.
+ //
+ // To get the inner value, we'd like to call `data.into_inner()`,
+ // but because `Mutex` impl-s `Drop`, we can't move out of it, so
+ // we'll have to destructure it manually instead.
+ unsafe {
+ // Like `let Mutex { inner, data } = self`.
+ let (inner, data) = {
+ let Mutex { ref inner, ref data } = self;
+ (ptr::read(inner), ptr::read(data))
+ };
+ mem::forget(self);
+ inner.lock.destroy(); // Keep in sync with the `Drop` impl.
+
+ poison::map_result(inner.poison.borrow(), |_| data.into_inner())
+ }
+ }
+
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows the `Mutex` mutably, no actual locking needs to
+ /// take place---the mutable borrow statically guarantees no locks exist.
+ ///
+ /// # Failure
+ ///
+ /// If another user of this mutex panicked while holding the mutex, then
+ /// this call will return an error instead.
+ #[unstable(feature = "mutex_get_mut", reason = "recently added", issue = "28968")]
+ pub fn get_mut(&mut self) -> LockResult<&mut T> {
+ // We know statically that there are no other references to `self`, so
+ // there's no need to lock the inner StaticMutex.
+ let data = unsafe { &mut *self.data.get() };
+ poison::map_result(self.inner.poison.borrow(), |_| data )
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for Mutex<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
// This is actually safe b/c we know that there is no further usage of
// this mutex (it's up to the user to arrange for a mutex to get
// dropped, that's not our job)
+ //
+ // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`.
unsafe { self.inner.lock.destroy() }
}
}
use sync::mpsc::channel;
use sync::{Arc, Mutex, StaticMutex, Condvar};
+ use sync::atomic::{AtomicUsize, Ordering};
use thread;
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
+ #[derive(Eq, PartialEq, Debug)]
+ struct NonCopy(i32);
+
unsafe impl<T: Send> Send for Packet<T> {}
unsafe impl<T> Sync for Packet<T> {}
*m.try_lock().unwrap() = ();
}
+ #[test]
+ fn test_into_inner() {
+ let m = Mutex::new(NonCopy(10));
+ assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+ }
+
+ #[test]
+ fn test_into_inner_drop() {
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = Mutex::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ {
+ let _inner = m.into_inner().unwrap();
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+
+ #[test]
+ fn test_into_inner_poison() {
+ let m = Arc::new(Mutex::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.lock().unwrap();
+ panic!("test panic in inner thread to poison mutex");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().into_inner() {
+ Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x),
+ }
+ }
+
+ #[test]
+ fn test_get_mut() {
+ let mut m = Mutex::new(NonCopy(10));
+ *m.get_mut().unwrap() = NonCopy(20);
+ assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+ }
+
+ #[test]
+ fn test_get_mut_poison() {
+ let m = Arc::new(Mutex::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.lock().unwrap();
+ panic!("test panic in inner thread to poison mutex");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().get_mut() {
+ Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x),
+ }
+ }
+
#[test]
fn test_mutex_arc_condvar() {
let packet = Packet(Arc::new((Mutex::new(false), Condvar::new())));
assert_eq!(*lock, 2);
}
- // FIXME(#25351) needs deeply nested coercions of DST structs.
- // #[test]
- // fn test_mutex_unsized() {
- // let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
- // {
- // let b = &mut *mutex.lock().unwrap();
- // b[0] = 4;
- // b[2] = 5;
- // }
- // let comp: &[i32] = &[4, 2, 5];
- // assert_eq!(&*mutex.lock().unwrap(), comp);
- // }
+ #[test]
+ fn test_mutex_unsized() {
+ let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]);
+ {
+ let b = &mut *mutex.lock().unwrap();
+ b[0] = 4;
+ b[2] = 5;
+ }
+ let comp: &[i32] = &[4, 2, 5];
+ assert_eq!(&*mutex.lock().unwrap(), comp);
+ }
}
use cell::UnsafeCell;
use fmt;
use marker;
+use mem;
use ops::{Deref, DerefMut};
+use ptr;
use sys_common::poison::{self, LockResult, TryLockError, TryLockResult};
use sys_common::rwlock as sys;
pub fn is_poisoned(&self) -> bool {
self.inner.poison.get()
}
+
+ /// Consumes this `RwLock`, returning the underlying data.
+ ///
+ /// # Failure
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ #[unstable(feature = "rwlock_into_inner", reason = "recently added", issue = "28968")]
+ pub fn into_inner(self) -> LockResult<T> where T: Sized {
+ // We know statically that there are no outstanding references to
+ // `self` so there's no need to lock the inner StaticRwLock.
+ //
+ // To get the inner value, we'd like to call `data.into_inner()`,
+ // but because `RwLock` impl-s `Drop`, we can't move out of it, so
+ // we'll have to destructure it manually instead.
+ unsafe {
+ // Like `let RwLock { inner, data } = self`.
+ let (inner, data) = {
+ let RwLock { ref inner, ref data } = self;
+ (ptr::read(inner), ptr::read(data))
+ };
+ mem::forget(self);
+ inner.lock.destroy(); // Keep in sync with the `Drop` impl.
+
+ poison::map_result(inner.poison.borrow(), |_| data.into_inner())
+ }
+ }
+
+ /// Returns a mutable reference to the underlying data.
+ ///
+ /// Since this call borrows the `RwLock` mutably, no actual locking needs to
+ /// take place---the mutable borrow statically guarantees no locks exist.
+ ///
+ /// # Failure
+ ///
+ /// This function will return an error if the RwLock is poisoned. An RwLock
+ /// is poisoned whenever a writer panics while holding an exclusive lock. An
+ /// error will only be returned if the lock would have otherwise been
+ /// acquired.
+ #[unstable(feature = "rwlock_get_mut", reason = "recently added", issue = "28968")]
+ pub fn get_mut(&mut self) -> LockResult<&mut T> {
+ // We know statically that there are no other references to `self`, so
+ // there's no need to lock the inner StaticRwLock.
+ let data = unsafe { &mut *self.data.get() };
+ poison::map_result(self.inner.poison.borrow(), |_| data )
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Drop for RwLock<T> {
+ #[unsafe_destructor_blind_to_params]
fn drop(&mut self) {
+ // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`.
unsafe { self.inner.lock.destroy() }
}
}
use sync::mpsc::channel;
use thread;
use sync::{Arc, RwLock, StaticRwLock, TryLockError};
+ use sync::atomic::{AtomicUsize, Ordering};
+
+ #[derive(Eq, PartialEq, Debug)]
+ struct NonCopy(i32);
#[test]
fn smoke() {
assert_eq!(*lock, 2);
}
- // FIXME(#25351) needs deeply nested coercions of DST structs.
- // #[test]
- // fn test_rwlock_unsized() {
- // let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
- // {
- // let b = &mut *rw.write().unwrap();
- // b[0] = 4;
- // b[2] = 5;
- // }
- // let comp: &[i32] = &[4, 2, 5];
- // assert_eq!(&*rw.read().unwrap(), comp);
- // }
+ #[test]
+ fn test_rwlock_unsized() {
+ let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]);
+ {
+ let b = &mut *rw.write().unwrap();
+ b[0] = 4;
+ b[2] = 5;
+ }
+ let comp: &[i32] = &[4, 2, 5];
+ assert_eq!(&*rw.read().unwrap(), comp);
+ }
#[test]
fn test_rwlock_try_write() {
drop(read_guard);
}
+
+ #[test]
+ fn test_into_inner() {
+ let m = RwLock::new(NonCopy(10));
+ assert_eq!(m.into_inner().unwrap(), NonCopy(10));
+ }
+
+ #[test]
+ fn test_into_inner_drop() {
+ struct Foo(Arc<AtomicUsize>);
+ impl Drop for Foo {
+ fn drop(&mut self) {
+ self.0.fetch_add(1, Ordering::SeqCst);
+ }
+ }
+ let num_drops = Arc::new(AtomicUsize::new(0));
+ let m = RwLock::new(Foo(num_drops.clone()));
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ {
+ let _inner = m.into_inner().unwrap();
+ assert_eq!(num_drops.load(Ordering::SeqCst), 0);
+ }
+ assert_eq!(num_drops.load(Ordering::SeqCst), 1);
+ }
+
+ #[test]
+ fn test_into_inner_poison() {
+ let m = Arc::new(RwLock::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.write().unwrap();
+ panic!("test panic in inner thread to poison RwLock");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().into_inner() {
+ Err(e) => assert_eq!(e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x),
+ }
+ }
+
+ #[test]
+ fn test_get_mut() {
+ let mut m = RwLock::new(NonCopy(10));
+ *m.get_mut().unwrap() = NonCopy(20);
+ assert_eq!(m.into_inner().unwrap(), NonCopy(20));
+ }
+
+ #[test]
+ fn test_get_mut_poison() {
+ let m = Arc::new(RwLock::new(NonCopy(10)));
+ let m2 = m.clone();
+ let _ = thread::spawn(move || {
+ let _lock = m2.write().unwrap();
+ panic!("test panic in inner thread to poison RwLock");
+ }).join();
+
+ assert!(m.is_poisoned());
+ match Arc::try_unwrap(m).unwrap().get_mut() {
+ Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)),
+ Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x),
+ }
+ }
}
#[link(name = "unwind", kind = "static")]
extern {}
-#[cfg(any(target_os = "android", target_os = "netbsd", target_os = "openbsd"))]
+#[cfg(any(target_os = "android", target_os = "openbsd"))]
#[link(name = "gcc")]
extern {}
+#[cfg(all(target_os = "netbsd", not(target_vendor = "rumprun")))]
+#[link(name = "gcc")]
+extern {}
+
+#[cfg(all(target_os = "netbsd", target_vendor = "rumprun"))]
+#[link(name = "unwind")]
+extern {}
+
#[cfg(target_os = "dragonfly")]
#[link(name = "gcc_pic")]
extern {}
use any::Any;
use boxed;
-use cell::Cell;
use cmp;
-use panicking;
+use panicking::{self,PANIC_COUNT};
use fmt;
use intrinsics;
use mem;
#[path = "seh.rs"] #[doc(hidden)]
pub mod imp;
+// stage0: i686-pc-windows-gnu
+#[cfg(all(stage0, windows, target_arch = "x86_64", target_env = "gnu"))]
+#[path = "seh64_gnu.rs"] #[doc(hidden)]
+pub mod imp;
+
+// stage0: x86_64-pc-windows-msvc
+#[cfg(all(stage0, windows, target_arch = "x86_64", target_env = "msvc"))]
+#[path = "seh.rs"] #[doc(hidden)]
+pub mod imp;
+
// x86_64-pc-windows-*
-#[cfg(all(windows, target_arch = "x86_64"))]
+#[cfg(all(not(stage0), windows, target_arch = "x86_64"))]
#[path = "seh64_gnu.rs"] #[doc(hidden)]
pub mod imp;
#[path = "gcc.rs"] #[doc(hidden)]
pub mod imp;
-pub type Callback = fn(msg: &(Any + Send), file: &'static str, line: u32);
-
-// Variables used for invoking callbacks when a thread starts to unwind.
-//
-// For more information, see below.
-const MAX_CALLBACKS: usize = 16;
-static CALLBACKS: [atomic::AtomicUsize; MAX_CALLBACKS] =
- [atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
- atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
- atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
- atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
- atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
- atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
- atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0),
- atomic::AtomicUsize::new(0), atomic::AtomicUsize::new(0)];
-static CALLBACK_CNT: atomic::AtomicUsize = atomic::AtomicUsize::new(0);
-
-thread_local! { static PANICKING: Cell<bool> = Cell::new(false) }
-
/// Invoke a closure, capturing the cause of panic if one occurs.
///
/// This function will return `Ok(())` if the closure did not panic, and will
// care of exposing correctly.
unsafe fn inner_try(f: fn(*mut u8), data: *mut u8)
-> Result<(), Box<Any + Send>> {
- let prev = PANICKING.with(|s| s.get());
- PANICKING.with(|s| s.set(false));
- let ep = intrinsics::try(f, data);
- PANICKING.with(|s| s.set(prev));
- if ep.is_null() {
- Ok(())
- } else {
- Err(imp::cleanup(ep))
- }
+ PANIC_COUNT.with(|s| {
+ let prev = s.get();
+ s.set(0);
+ let ep = intrinsics::try(f, data);
+ s.set(prev);
+ if ep.is_null() {
+ Ok(())
+ } else {
+ Err(imp::cleanup(ep))
+ }
+ })
}
fn try_fn<F: FnOnce()>(opt_closure: *mut u8) {
/// Determines whether the current thread is unwinding because of panic.
pub fn panicking() -> bool {
- PANICKING.with(|s| s.get())
+ PANIC_COUNT.with(|s| s.get() != 0)
}
// An uninlined, unmangled function upon which to slap yer breakpoints
#[inline(never)] #[cold] // this is the slow path, please never inline this
fn begin_unwind_inner(msg: Box<Any + Send>,
file_line: &(&'static str, u32)) -> ! {
- // Make sure the default failure handler is registered before we look at the
- // callbacks. We also use a raw sys-based mutex here instead of a
- // `std::sync` one as accessing TLS can cause weird recursive problems (and
- // we don't need poison checking).
- unsafe {
- static LOCK: Mutex = Mutex::new();
- static mut INIT: bool = false;
- LOCK.lock();
- if !INIT {
- register(panicking::on_panic);
- INIT = true;
- }
- LOCK.unlock();
- }
+ let (file, line) = *file_line;
- // First, invoke call the user-defined callbacks triggered on thread panic.
- //
- // By the time that we see a callback has been registered (by reading
- // MAX_CALLBACKS), the actual callback itself may have not been stored yet,
- // so we just chalk it up to a race condition and move on to the next
- // callback. Additionally, CALLBACK_CNT may briefly be higher than
- // MAX_CALLBACKS, so we're sure to clamp it as necessary.
- let callbacks = {
- let amt = CALLBACK_CNT.load(Ordering::SeqCst);
- &CALLBACKS[..cmp::min(amt, MAX_CALLBACKS)]
- };
- for cb in callbacks {
- match cb.load(Ordering::SeqCst) {
- 0 => {}
- n => {
- let f: Callback = unsafe { mem::transmute(n) };
- let (file, line) = *file_line;
- f(&*msg, file, line);
- }
- }
- };
+ // First, invoke the default panic handler.
+ panicking::on_panic(&*msg, file, line);
- // Now that we've run all the necessary unwind callbacks, we actually
- // perform the unwinding.
- if panicking() {
- // If a thread panics while it's already unwinding then we
- // have limited options. Currently our preference is to
- // just abort. In the future we may consider resuming
- // unwinding or otherwise exiting the thread cleanly.
- super::util::dumb_print(format_args!("thread panicked while panicking. \
- aborting."));
- unsafe { intrinsics::abort() }
- }
- PANICKING.with(|s| s.set(true));
+ // Finally, perform the unwinding.
rust_panic(msg);
}
-
-/// Register a callback to be invoked when a thread unwinds.
-///
-/// This is an unsafe and experimental API which allows for an arbitrary
-/// callback to be invoked when a thread panics. This callback is invoked on both
-/// the initial unwinding and a double unwinding if one occurs. Additionally,
-/// the local `Thread` will be in place for the duration of the callback, and
-/// the callback must ensure that it remains in place once the callback returns.
-///
-/// Only a limited number of callbacks can be registered, and this function
-/// returns whether the callback was successfully registered or not. It is not
-/// currently possible to unregister a callback once it has been registered.
-pub unsafe fn register(f: Callback) -> bool {
- match CALLBACK_CNT.fetch_add(1, Ordering::SeqCst) {
- // The invocation code has knowledge of this window where the count has
- // been incremented, but the callback has not been stored. We're
- // guaranteed that the slot we're storing into is 0.
- n if n < MAX_CALLBACKS => {
- let prev = CALLBACKS[n].swap(mem::transmute(f), Ordering::SeqCst);
- rtassert!(prev == 0);
- true
- }
- // If we accidentally bumped the count too high, pull it back.
- _ => {
- CALLBACK_CNT.store(MAX_CALLBACKS, Ordering::SeqCst);
- false
- }
- }
-}
use ascii::*;
use borrow::Cow;
use char;
-use cmp;
use fmt;
use hash::{Hash, Hasher};
use iter::FromIterator;
}
impl Wtf8Buf {
- /// Creates an new, empty WTF-8 string.
+ /// Creates a new, empty WTF-8 string.
#[inline]
pub fn new() -> Wtf8Buf {
Wtf8Buf { bytes: Vec::new() }
}
- /// Creates an new, empty WTF-8 string with pre-allocated capacity for `n` bytes.
+ /// Creates a new, empty WTF-8 string with pre-allocated capacity for `n` bytes.
#[inline]
pub fn with_capacity(n: usize) -> Wtf8Buf {
Wtf8Buf { bytes: Vec::with_capacity(n) }
///
/// Similar to `&str`, but can additionally contain surrogate code points
/// if they’re not in a surrogate pair.
+#[derive(Eq, Ord, PartialEq, PartialOrd)]
pub struct Wtf8 {
bytes: [u8]
}
fn as_inner(&self) -> &[u8] { &self.bytes }
}
-// FIXME: https://github.com/rust-lang/rust/issues/18805
-impl PartialEq for Wtf8 {
- fn eq(&self, other: &Wtf8) -> bool { self.bytes.eq(&other.bytes) }
-}
-
-// FIXME: https://github.com/rust-lang/rust/issues/18805
-impl Eq for Wtf8 {}
-
-// FIXME: https://github.com/rust-lang/rust/issues/18738
-impl PartialOrd for Wtf8 {
- #[inline]
- fn partial_cmp(&self, other: &Wtf8) -> Option<cmp::Ordering> {
- self.bytes.partial_cmp(&other.bytes)
- }
- #[inline]
- fn lt(&self, other: &Wtf8) -> bool { self.bytes.lt(&other.bytes) }
- #[inline]
- fn le(&self, other: &Wtf8) -> bool { self.bytes.le(&other.bytes) }
- #[inline]
- fn gt(&self, other: &Wtf8) -> bool { self.bytes.gt(&other.bytes) }
- #[inline]
- fn ge(&self, other: &Wtf8) -> bool { self.bytes.ge(&other.bytes) }
-}
-
-// FIXME: https://github.com/rust-lang/rust/issues/18738
-impl Ord for Wtf8 {
- #[inline]
- fn cmp(&self, other: &Wtf8) -> cmp::Ordering { self.bytes.cmp(&other.bytes) }
-}
-
/// Format the slice with double quotes,
/// and surrogates as `\u` followed by four hexadecimal digits.
/// Example: `"a\u{D800}"` for a slice with code points [U+0061, U+D800]
fn wtf8buf_from_iterator() {
fn f(values: &[u32]) -> Wtf8Buf {
values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::<Wtf8Buf>()
- };
+ }
assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9");
assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic!
let mut string = initial.iter().map(c).collect::<Wtf8Buf>();
string.extend(extended.iter().map(c));
string
- };
+ }
assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes,
b"a\xC3\xA9 \xF0\x9F\x92\xA9");
target_os = "dragonfly"))]
pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 71;
#[cfg(any(target_os = "bitrig",
- target_os = "netbsd",
target_os = "openbsd"))]
pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 101;
+#[cfg(target_os = "netbsd")]
+pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 48;
#[cfg(target_os = "android")]
pub const _SC_GETPW_R_SIZE_MAX: libc::c_int = 0x0048;
pub fn raise(signum: libc::c_int) -> libc::c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__sigaction14")]
pub fn sigaction(signum: libc::c_int,
act: *const sigaction,
oldact: *mut sigaction) -> libc::c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__sigaltstack14")]
pub fn sigaltstack(ss: *const sigaltstack,
oss: *mut sigaltstack) -> libc::c_int;
#[cfg(not(target_os = "android"))]
+ #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")]
pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
pub fn pthread_sigmask(how: libc::c_int, set: *const sigset_t,
oldset: *mut sigset_t) -> libc::c_int;
#[cfg(not(target_os = "ios"))]
+ #[cfg_attr(target_os = "netbsd", link_name = "__getpwuid_r50")]
pub fn getpwuid_r(uid: libc::uid_t,
pwd: *mut passwd,
buf: *mut libc::c_char,
buflen: libc::size_t,
result: *mut *mut passwd) -> libc::c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__utimes50")]
pub fn utimes(filename: *const libc::c_char,
times: *const libc::timeval) -> libc::c_int;
pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
#[cfg(any(target_os = "macos",
target_os = "ios"))]
pub type sigset_t = u32;
- #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+ #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))]
#[repr(C)]
pub struct sigset_t {
bits: [u32; 4],
}
- #[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))]
+ #[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
pub type sigset_t = libc::c_uint;
// This structure has more fields, but we're not all that interested in
}
/// Add special unix types (block/char device, fifo and socket)
-#[unstable(feature = "file_type_ext", reason = "recently added API",
- issue = "27796")]
+#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_block_device(&self) -> bool;
/// Returns whether this file type is a char device.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_char_device(&self) -> bool;
/// Returns whether this file type is a fifo.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_fifo(&self) -> bool;
/// Returns whether this file type is a socket.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_socket(&self) -> bool;
}
-#[unstable(feature = "file_type_ext", reason = "recently added API",
- issue = "27796")]
+#[stable(feature = "file_type_ext", since = "1.5.0")]
impl FileTypeExt for fs::FileType {
fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
/// This is not enough to create a daemon process. The *init* process should
/// be the child reaper of a daemon. This can be achieved if the parent
/// process exit. Moreover, a daemon should not have a controlling terminal.
- /// To acheive this, a session leader (the child) must spawn another process
+ /// To achieve this, a session leader (the child) must spawn another process
/// (the daemon) in the same session.
#[unstable(feature = "process_session_leader", reason = "recently added",
issue = "27811")]
pub struct File(FileDesc);
+#[derive(Clone)]
pub struct FileAttr {
stat: raw::stat,
}
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
- use fs::{File, PathExt, set_permissions};
+ use fs::{File, set_permissions};
if !from.is_file() {
return Err(Error::new(ErrorKind::InvalidInput,
"the source path is not an existing regular file"))
pub mod stdio;
pub fn init() {
- // By default, some platforms will send a *signal* when a EPIPE error
+ // By default, some platforms will send a *signal* when an EPIPE error
// would otherwise be delivered. This runtime doesn't install a SIGPIPE
// handler, causing it to kill the program, which isn't exactly what we
// want!
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
- let mut mib = vec![CTL_KERN as c_int,
- KERN_PROC as c_int,
- KERN_PROC_PATHNAME as c_int,
- -1 as c_int];
+ let mut mib = [CTL_KERN as c_int,
+ KERN_PROC as c_int,
+ KERN_PROC_PATHNAME as c_int,
+ -1 as c_int];
let mut sz: libc::size_t = 0;
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
ptr::null_mut(), &mut sz, ptr::null_mut(),
::fs::read_link("/proc/curproc/file")
}
-#[cfg(any(target_os = "bitrig", target_os = "netbsd", target_os = "openbsd"))]
+#[cfg(target_os = "netbsd")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ ::fs::read_link("/proc/curproc/exe")
+}
+
+#[cfg(any(target_os = "bitrig", target_os = "openbsd"))]
pub fn current_exe() -> io::Result<PathBuf> {
use sync::StaticMutex;
static LOCK: StaticMutex = StaticMutex::new();
let args = objc_msgSend(info, arguments_sel);
let cnt: usize = mem::transmute(objc_msgSend(args, count_sel));
- for i in (0..cnt) {
+ for i in 0..cnt {
let tmp = objc_msgSend(args, object_at_sel, i);
let utf_c_str: *const libc::c_char =
mem::transmute(objc_msgSend(tmp, utf8_sel));
use slice;
use sys::{self, c, cvt, pipe};
+ macro_rules! t {
+ ($e:expr) => {
+ match $e {
+ Ok(t) => t,
+ Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+ }
+ }
+ }
+
#[cfg(not(target_os = "android"))]
extern {
+ #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
fn sigaddset(set: *mut c::sigset_t, signum: libc::c_int) -> libc::c_int;
}
unsafe {
// Test to make sure that a signal mask does not get inherited.
let cmd = Command::new(OsStr::new("cat"));
- let (stdin_read, stdin_write) = sys::pipe::anon_pipe().unwrap();
- let (stdout_read, stdout_write) = sys::pipe::anon_pipe().unwrap();
+ let (stdin_read, stdin_write) = t!(sys::pipe::anon_pipe());
+ let (stdout_read, stdout_write) = t!(sys::pipe::anon_pipe());
let mut set: c::sigset_t = mem::uninitialized();
let mut old_set: c::sigset_t = mem::uninitialized();
- cvt(c::sigemptyset(&mut set)).unwrap();
- cvt(sigaddset(&mut set, libc::SIGINT)).unwrap();
- cvt(c::pthread_sigmask(c::SIG_SETMASK, &set, &mut old_set)).unwrap();
+ t!(cvt(c::sigemptyset(&mut set)));
+ t!(cvt(sigaddset(&mut set, libc::SIGINT)));
+ t!(cvt(c::pthread_sigmask(c::SIG_SETMASK, &set, &mut old_set)));
- let cat = Process::spawn(&cmd, Stdio::Raw(stdin_read.raw()),
- Stdio::Raw(stdout_write.raw()),
- Stdio::None).unwrap();
+ let cat = t!(Process::spawn(&cmd, Stdio::Raw(stdin_read.raw()),
+ Stdio::Raw(stdout_write.raw()),
+ Stdio::None));
drop(stdin_read);
drop(stdout_write);
- cvt(c::pthread_sigmask(c::SIG_SETMASK, &old_set, ptr::null_mut())).unwrap();
+ t!(cvt(c::pthread_sigmask(c::SIG_SETMASK, &old_set,
+ ptr::null_mut())));
- cvt(libc::funcs::posix88::signal::kill(cat.id() as libc::pid_t, libc::SIGINT)).unwrap();
+ t!(cvt(libc::funcs::posix88::signal::kill(cat.id() as libc::pid_t,
+ libc::SIGINT)));
// We need to wait until SIGINT is definitely delivered. The
// easiest way is to write something to cat, and try to read it
// back: if SIGINT is unmasked, it'll get delivered when cat is
assert!(ret == 0);
}
- cat.wait().unwrap();
+ t!(cat.wait());
}
}
}
#[cfg(any(target_os = "linux",
target_os = "macos",
target_os = "bitrig",
- target_os = "netbsd",
+ all(target_os = "netbsd", not(target_vendor = "rumprun")),
target_os = "openbsd"))]
mod imp {
use super::Handler;
#[cfg(not(any(target_os = "linux",
target_os = "macos",
target_os = "bitrig",
- target_os = "netbsd",
+ all(target_os = "netbsd", not(target_vendor = "rumprun")),
target_os = "openbsd")))]
mod imp {
use ptr;
pub fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
pub fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> libc::c_int;
pub fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
+ #[cfg_attr(target_os = "netbsd", link_name = "__gettimeofday50")]
pub fn gettimeofday(tp: *mut libc::timeval,
tz: *mut libc::c_void) -> libc::c_int;
#[cfg(any(target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig",
- target_os = "netbsd",
target_os = "openbsd"))]
mod os {
use libc;
};
pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 1;
}
+
+#[cfg(target_os = "netbsd")]
+mod os {
+ use libc;
+
+ // size of the type minus width of the magic and alignment field
+ #[cfg(target_arch = "x86_64")]
+ const __PTHREAD_MUTEX_SIZE__: usize = 48 - 4 - 8;
+
+ #[cfg(target_arch = "x86_64")]
+ const __PTHREAD_MUTEXATTR_SIZE__: usize = 16 - 8; // no magic field
+
+ #[cfg(target_arch = "x86_64")]
+ const __PTHREAD_COND_SIZE__: usize = 40 - 4 - 8;
+
+ #[cfg(target_arch = "x86_64")]
+ const __PTHREAD_RWLOCK_SIZE__: usize = 64 - 4 - 8;
+
+ const _PTHREAD_MUTEX_MAGIC_INIT: libc::c_uint = 0x33330003;
+ const _PTHREAD_COND_MAGIC_INIT: libc::c_uint = 0x55550005;
+ const _PTHREAD_RWLOCK_MAGIC_INIT: libc::c_uint = 0x99990009;
+
+ #[repr(C)]
+ pub struct pthread_mutex_t {
+ __magic: libc::c_uint,
+ __opaque: [u8; __PTHREAD_MUTEX_SIZE__],
+ __align: libc::c_longlong,
+ }
+ #[repr(C)]
+ pub struct pthread_mutexattr_t {
+ __opaque: [u8; __PTHREAD_MUTEXATTR_SIZE__],
+ __align: libc::c_longlong,
+ }
+ #[repr(C)]
+ pub struct pthread_cond_t {
+ __magic: libc::c_uint,
+ __opaque: [u8; __PTHREAD_COND_SIZE__],
+ __align: libc::c_longlong,
+ }
+ #[repr(C)]
+ pub struct pthread_rwlock_t {
+ __magic: libc::c_uint,
+ __opaque: [u8; __PTHREAD_RWLOCK_SIZE__],
+ __align: libc::c_longlong,
+ }
+
+ pub const PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
+ __magic: _PTHREAD_MUTEX_MAGIC_INIT,
+ __opaque: [0; __PTHREAD_MUTEX_SIZE__],
+ __align: 0,
+ };
+ pub const PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
+ __magic: _PTHREAD_COND_MAGIC_INIT,
+ __opaque: [0; __PTHREAD_COND_SIZE__],
+ __align: 0,
+ };
+ pub const PTHREAD_RWLOCK_INITIALIZER: pthread_rwlock_t = pthread_rwlock_t {
+ __magic: _PTHREAD_RWLOCK_MAGIC_INIT,
+ __opaque: [0; __PTHREAD_RWLOCK_SIZE__],
+ __align: 0,
+ };
+
+ pub const PTHREAD_MUTEX_RECURSIVE: libc::c_int = 2;
+}
#[cfg(any(target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig",
- target_os = "netbsd",
target_os = "openbsd"))]
pub fn set_name(name: &str) {
extern {
}
}
+ #[cfg(target_os = "netbsd")]
+ pub fn set_name(name: &str) {
+ extern {
+ fn pthread_setname_np(thread: libc::pthread_t,
+ name: *const libc::c_char,
+ arg: *mut libc::c_void) -> libc::c_int;
+ }
+ let cname = CString::new(&b"%s"[..]).unwrap();
+ let carg = CString::new(name).unwrap();
+ unsafe {
+ pthread_setname_np(pthread_self(), cname.as_ptr(),
+ carg.as_ptr() as *mut libc::c_void);
+ }
+ }
+
pub fn sleep(dur: Duration) {
let mut ts = libc::timespec {
tv_sec: dur.as_secs() as libc::time_t,
#[cfg(all(not(target_os = "linux"),
not(target_os = "macos"),
not(target_os = "bitrig"),
- not(target_os = "netbsd"),
+ not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
not(target_os = "openbsd")))]
pub mod guard {
pub unsafe fn current() -> Option<usize> { None }
#[cfg(any(target_os = "linux",
target_os = "macos",
target_os = "bitrig",
- target_os = "netbsd",
+ all(target_os = "netbsd", not(target_vendor = "rumprun")),
target_os = "openbsd"))]
#[allow(unused_imports)]
pub mod guard {
#[cfg(any(target_os = "macos",
target_os = "bitrig",
- target_os = "netbsd",
target_os = "openbsd"))]
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
current().map(|s| s as *mut libc::c_void)
}
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
use super::pthread_attr_init;
pthread_get_stacksize_np(pthread_self())) as usize)
}
- #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "bitrig"))]
+ #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
pub unsafe fn current() -> Option<usize> {
#[repr(C)]
struct stack_t {
})
}
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
pub unsafe fn current() -> Option<usize> {
use super::pthread_attr_init;
let mut size = 0;
assert_eq!(pthread_attr_getstack(&attr, &mut stackaddr, &mut size), 0);
- ret = Some(stackaddr as usize + guardsize as usize);
+ ret = if cfg!(target_os = "netbsd") {
+ Some(stackaddr as usize)
+ } else {
+ Some(stackaddr as usize + guardsize as usize)
+ };
}
assert_eq!(pthread_attr_destroy(&mut attr), 0);
ret
}
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "netbsd"))]
extern {
fn pthread_getattr_np(native: libc::pthread_t,
attr: *mut libc::pthread_attr_t) -> libc::c_int;
// but that caused Debian to detect an unnecessarily strict versioned
// dependency on libc6 (#23628).
#[cfg(target_os = "linux")]
+#[allow(deprecated)]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
use dynamic_lib::DynamicLibrary;
use sync::Once;
#[link(name = "rt")]
extern {}
+
extern {
+ #[cfg_attr(target_os = "netbsd", link_name = "__clock_gettime50")]
fn clock_gettime(clk_id: libc::c_int, tp: *mut libc::timespec) -> libc::c_int;
}
//! copy of that function in my mingw install (maybe it was broken?). Instead,
//! this takes the route of using StackWalk64 in order to walk the stack.
-#![allow(dead_code)]
+#![allow(dead_code, deprecated)]
use io::prelude::*;
pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
+pub const ERROR_PATH_NOT_FOUND: libc::c_int = 3;
+
#[repr(C)]
#[cfg(target_arch = "x86")]
pub struct WSADATA {
pub type PCONSOLE_SCREEN_BUFFER_INFO = *mut CONSOLE_SCREEN_BUFFER_INFO;
#[repr(C)]
+#[derive(Clone)]
pub struct WIN32_FILE_ATTRIBUTE_DATA {
pub dwFileAttributes: libc::DWORD,
pub ftCreationTime: libc::FILETIME,
pub struct File { handle: Handle }
+#[derive(Clone)]
pub struct FileAttr {
data: c::WIN32_FILE_ATTRIBUTE_DATA,
reparse_tag: libc::DWORD,
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
let mut opts = OpenOptions::new();
opts.read(true);
+ // This flag is so we can open directories too
+ opts.flags_and_attributes(c::FILE_FLAG_BACKUP_SEMANTICS);
let f = try!(File::open(p, &opts));
get_path(&f)
}
libc::ERROR_ALREADY_EXISTS => ErrorKind::AlreadyExists,
libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe,
libc::ERROR_FILE_NOT_FOUND => ErrorKind::NotFound,
+ c::ERROR_PATH_NOT_FOUND => ErrorKind::NotFound,
libc::ERROR_NO_DATA => ErrorKind::BrokenPipe,
libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut,
v
}
-// Many Windows APIs follow a pattern of where we hand the a buffer and then
-// they will report back to us how large the buffer should be or how many bytes
+// Many Windows APIs follow a pattern of where we hand a buffer and then they
+// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
//! more details.
//!
//! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
-//! is there there are no guarantees of fairness.
+//! is that there are no guarantees of fairness.
//!
//! The downside of this approach, however, is that SRWLock is not available on
//! Windows XP, so we continue to have a fallback implementation where
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(deprecated)]
+
use dynamic_lib::DynamicLibrary;
use io;
use io::prelude::*;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(deprecated)]
+
use sys_common::backtrace::{output, output_fileline};
use ffi::CStr;
use dynamic_lib::DynamicLibrary;
use prelude::v1::*;
-use alloc::boxed::FnBox;
use any::Any;
use cell::UnsafeCell;
use fmt;
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
{
- unsafe {
- self.spawn_inner(Box::new(f)).map(JoinHandle)
- }
- }
-
- // NB: this function is unsafe as the lifetime parameter of the code to run
- // in the new thread is not tied into the return value, and the return
- // value must not outlast that lifetime.
- unsafe fn spawn_inner<'a, T: Send>(self, f: Box<FnBox() -> T + Send + 'a>)
- -> io::Result<JoinInner<T>> {
let Builder { name, stack_size } = self;
let stack_size = stack_size.unwrap_or(util::min_stack());
let my_thread = Thread::new(name);
let their_thread = my_thread.clone();
- let my_packet = Arc::new(UnsafeCell::new(None));
+ let my_packet : Arc<UnsafeCell<Option<Result<T>>>>
+ = Arc::new(UnsafeCell::new(None));
let their_packet = my_packet.clone();
let main = move || {
if let Some(name) = their_thread.name() {
imp::Thread::set_name(name);
}
- thread_info::set(imp::guard::current(), their_thread);
- let mut output = None;
- let try_result = {
- let ptr = &mut output;
- unwind::try(move || *ptr = Some(f()))
- };
- *their_packet.get() = Some(try_result.map(|()| {
- output.unwrap()
- }));
+ unsafe {
+ thread_info::set(imp::guard::current(), their_thread);
+ let mut output = None;
+ let try_result = {
+ let ptr = &mut output;
+ unwind::try(move || *ptr = Some(f()))
+ };
+ *their_packet.get() = Some(try_result.map(|()| {
+ output.unwrap()
+ }));
+ }
};
- Ok(JoinInner {
- native: Some(try!(imp::Thread::new(stack_size, Box::new(main)))),
+ Ok(JoinHandle(JoinInner {
+ native: unsafe {
+ Some(try!(imp::Thread::new(stack_size, Box::new(main))))
+ },
thread: my_thread,
packet: Packet(my_packet),
- })
+ }))
}
}
}
impl Duration {
- /// Crates a new `Duration` from the specified number of seconds and
+ /// Creates a new `Duration` from the specified number of seconds and
/// additional nanosecond precision.
///
/// If the nanoseconds is greater than 1 billion (the number of nanoseconds
// The Rust abstract syntax tree.
-pub use self::AsmDialect::*;
-pub use self::AttrStyle::*;
pub use self::BindingMode::*;
pub use self::BinOp_::*;
pub use self::BlockCheckMode::*;
pub use self::KleeneOp::*;
pub use self::Lit_::*;
pub use self::LitIntType::*;
-pub use self::Mac_::*;
pub use self::MacStmtStyle::*;
pub use self::MetaItem_::*;
pub use self::Mutability::*;
pub use self::UintTy::*;
pub use self::UnOp::*;
pub use self::UnsafeSource::*;
-pub use self::VariantKind::*;
pub use self::ViewPath_::*;
pub use self::Visibility::*;
pub use self::PathParameters::*;
use std::fmt;
use std::rc::Rc;
+use std::borrow::Cow;
+use std::hash::{Hash, Hasher};
use serialize::{Encodable, Decodable, Encoder, Decoder};
-// FIXME #6993: in librustc, uses of "ident" should be replaced
-// by just "Name".
+/// A name is a part of an identifier, representing a string or gensym. It's
+/// the result of interning.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Name(pub u32);
+
+/// A SyntaxContext represents a chain of macro-expandings
+/// and renamings. Each macro expansion corresponds to
+/// a fresh u32. This u32 is a reference to a table stored
+// in thread-local storage.
+// The special value EMPTY_CTXT is used to indicate an empty
+// syntax context.
+#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
+pub struct SyntaxContext(pub u32);
/// An identifier contains a Name (index into the interner
/// table) and a SyntaxContext to track renaming and
-/// macro expansion per Flatt et al., "Macros
-/// That Work Together"
-#[derive(Clone, Copy, Hash, PartialOrd, Eq, Ord)]
+/// macro expansion per Flatt et al., "Macros That Work Together"
+#[derive(Clone, Copy, Eq)]
pub struct Ident {
pub name: Name,
pub ctxt: SyntaxContext
}
-impl Ident {
- /// Construct an identifier with the given name and an empty context:
- pub fn new(name: Name) -> Ident { Ident {name: name, ctxt: EMPTY_CTXT}}
-}
-
-impl fmt::Debug for Ident {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}#{}", self.name, self.ctxt)
- }
-}
-
-impl fmt::Display for Ident {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Display::fmt(&self.name, f)
+impl Name {
+ pub fn as_str(self) -> token::InternedString {
+ token::InternedString::new_from_name(self)
}
}
impl fmt::Debug for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let Name(nm) = *self;
- write!(f, "{}({})", self, nm)
+ write!(f, "{}({})", self, self.0)
}
}
}
}
-impl PartialEq for Ident {
- fn eq(&self, other: &Ident) -> bool {
- if self.ctxt == other.ctxt {
- self.name == other.name
- } else {
- // IF YOU SEE ONE OF THESE FAILS: it means that you're comparing
- // idents that have different contexts. You can't fix this without
- // knowing whether the comparison should be hygienic or non-hygienic.
- // if it should be non-hygienic (most things are), just compare the
- // 'name' fields of the idents. Or, even better, replace the idents
- // with Name's.
- //
- // On the other hand, if the comparison does need to be hygienic,
- // one example and its non-hygienic counterpart would be:
- // syntax::parse::token::Token::mtwt_eq
- // syntax::ext::tt::macro_parser::token_name_eq
- panic!("not allowed to compare these idents: {:?}, {:?}. \
- Probably related to issue \\#6993", self, other);
- }
+impl Encodable for Name {
+ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+ s.emit_str(&self.as_str())
}
}
-/// A SyntaxContext represents a chain of macro-expandings
-/// and renamings. Each macro expansion corresponds to
-/// a fresh u32
+impl Decodable for Name {
+ fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
+ Ok(token::intern(&try!(d.read_str())[..]))
+ }
+}
-// I'm representing this syntax context as an index into
-// a table, in order to work around a compiler bug
-// that's causing unreleased memory to cause core dumps
-// and also perhaps to save some work in destructor checks.
-// the special uint '0' will be used to indicate an empty
-// syntax context.
+pub const EMPTY_CTXT : SyntaxContext = SyntaxContext(0);
-// this uint is a reference to a table stored in thread-local
-// storage.
-pub type SyntaxContext = u32;
-pub const EMPTY_CTXT : SyntaxContext = 0;
-pub const ILLEGAL_CTXT : SyntaxContext = 1;
+impl Ident {
+ pub fn new(name: Name, ctxt: SyntaxContext) -> Ident {
+ Ident {name: name, ctxt: ctxt}
+ }
+ pub fn with_empty_ctxt(name: Name) -> Ident {
+ Ident {name: name, ctxt: EMPTY_CTXT}
+ }
+}
-/// A name is a part of an identifier, representing a string or gensym. It's
-/// the result of interning.
-#[derive(Eq, Ord, PartialEq, PartialOrd, Hash,
- RustcEncodable, RustcDecodable, Clone, Copy)]
-pub struct Name(pub u32);
+impl PartialEq for Ident {
+ fn eq(&self, other: &Ident) -> bool {
+ if self.ctxt != other.ctxt {
+ // There's no one true way to compare Idents. They can be compared
+ // non-hygienically `id1.name == id2.name`, hygienically
+ // `mtwt::resolve(id1) == mtwt::resolve(id2)`, or even member-wise
+ // `(id1.name, id1.ctxt) == (id2.name, id2.ctxt)` depending on the situation.
+ // Ideally, PartialEq should not be implemented for Ident at all, but that
+ // would be too impractical, because many larger structures (Token, in particular)
+ // including Idents as their parts derive PartialEq and use it for non-hygienic
+ // comparisons. That's why PartialEq is implemented and defaults to non-hygienic
+ // comparison. Hash is implemented too and is consistent with PartialEq, i.e. only
+ // the name of Ident is hashed. Still try to avoid comparing idents in your code
+ // (especially as keys in hash maps), use one of the three methods listed above
+ // explicitly.
+ //
+ // If you see this panic, then some idents from different contexts were compared
+ // non-hygienically. It's likely a bug. Use one of the three comparison methods
+ // listed above explicitly.
-impl<T: AsRef<str>> PartialEq<T> for Name {
- fn eq(&self, other: &T) -> bool {
- self.as_str() == other.as_ref()
+ panic!("idents with different contexts are compared with operator `==`: \
+ {:?}, {:?}.", self, other);
+ }
+
+ self.name == other.name
}
}
-impl Name {
- pub fn as_str(&self) -> token::InternedString {
- token::InternedString::new_from_name(*self)
+impl Hash for Ident {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.name.hash(state)
}
+}
- pub fn usize(&self) -> usize {
- let Name(nm) = *self;
- nm as usize
+impl fmt::Debug for Ident {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}#{}", self.name, self.ctxt.0)
}
+}
- pub fn ident(&self) -> Ident {
- Ident { name: *self, ctxt: 0 }
+impl fmt::Display for Ident {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.name, f)
}
}
-/// A mark represents a unique id associated with a macro expansion
-pub type Mrk = u32;
-
impl Encodable for Ident {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
- s.emit_str(&self.name.as_str())
+ self.name.encode(s)
}
}
impl Decodable for Ident {
fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
- Ok(str_to_ident(&try!(d.read_str())[..]))
+ Ok(Ident::with_empty_ctxt(try!(Name::decode(d))))
}
}
-/// Function name (not all functions have names)
-pub type FnIdent = Option<Ident>;
+/// A mark represents a unique id associated with a macro expansion
+pub type Mrk = u32;
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
pub struct Lifetime {
/// small, positive ids.
pub const DUMMY_NODE_ID: NodeId = !0;
+pub trait NodeIdAssigner {
+ fn next_node_id(&self) -> NodeId;
+ fn peek_node_id(&self) -> NodeId;
+}
+
/// The AST represents all type param bounds as types.
/// typeck::collect::compute_bounds matches these against
/// the "special" built-in traits (see middle::lang_items) and
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum UnOp {
- /// The `box` operator
- UnUniq,
/// The `*` operator for dereferencing
UnDeref,
/// The `!` operator for logical inversion
impl fmt::Debug for Stmt {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "stmt({}: {})",
- ast_util::stmt_id(self),
+ ast_util::stmt_id(self)
+ .map_or(Cow::Borrowed("<macro>"),|id|Cow::Owned(id.to_string())),
pprust::stmt_to_string(self))
}
}
pub enum BlockCheckMode {
DefaultBlock,
UnsafeBlock(UnsafeSource),
- PushUnsafeBlock(UnsafeSource),
- PopUnsafeBlock(UnsafeSource),
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Expr_ {
+ /// A `box x` expression.
+ ExprBox(P<Expr>),
/// First expr is the place; second expr is the value.
- ExprBox(Option<P<Expr>>, P<Expr>),
+ ExprInPlace(P<Expr>, P<Expr>),
/// An array (`[a, b, c, d]`)
ExprVec(Vec<P<Expr>>),
/// A function call
///
/// This is desugared to a `match` expression.
ExprIfLet(P<Pat>, P<Expr>, P<Block>, Option<P<Expr>>),
- // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
/// A while loop, with an optional label
///
/// `'label: while expr { block }`
ExprWhile(P<Expr>, P<Block>, Option<Ident>),
- // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
/// A while-let loop, with an optional label
///
/// `'label: while let pat = expr { block }`
///
/// This is desugared to a combination of `loop` and `match` expressions.
ExprWhileLet(P<Pat>, P<Expr>, P<Block>, Option<Ident>),
- // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
/// A for loop, with an optional label
///
/// `'label: for pat in expr { block }`
/// Conditionless loop (can be exited with break, continue, or return)
///
/// `'label: loop { block }`
- // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
ExprLoop(P<Block>, Option<Ident>),
- /// A `match` block, with a source that indicates whether or not it is
- /// the result of a desugaring, and if so, which kind.
- ExprMatch(P<Expr>, Vec<Arm>, MatchSource),
+ /// A `match` block.
+ ExprMatch(P<Expr>, Vec<Arm>),
/// A closure (for example, `move |a, b, c| {a + b + c}`)
ExprClosure(CaptureClause, P<FnDecl>, P<Block>),
/// A block (`{ ... }`)
pub position: usize
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum MatchSource {
- Normal,
- IfLetDesugar { contains_else_clause: bool },
- WhileLetDesugar,
- ForLoopDesugar,
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum CaptureClause {
CaptureByValue,
match *self {
TtToken(_, token::DocComment(name)) => {
match doc_comment_style(&name.as_str()) {
- AttrOuter => 2,
- AttrInner => 3
+ AttrStyle::Outer => 2,
+ AttrStyle::Inner => 3
}
}
TtToken(_, token::SpecialVarNt(..)) => 2,
TtToken(sp, token::Pound)
}
(&TtToken(sp, token::DocComment(name)), 1)
- if doc_comment_style(&name.as_str()) == AttrInner => {
+ if doc_comment_style(&name.as_str()) == AttrStyle::Inner => {
TtToken(sp, token::Not)
}
(&TtToken(sp, token::DocComment(name)), _) => {
/// is being invoked, and the vector of token-trees contains the source
/// of the macro invocation.
///
-/// There's only one flavor, now, so this could presumably be simplified.
+/// NB: the additional ident for a macro_rules-style macro is actually
+/// stored in the enclosing item. Oog.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum Mac_ {
- // NB: the additional ident for a macro_rules-style macro is actually
- // stored in the enclosing item. Oog.
- MacInvocTT(Path, Vec<TokenTree>, SyntaxContext), // new macro-invocation
+pub struct Mac_ {
+ pub path: Path,
+ pub tts: Vec<TokenTree>,
+ pub ctxt: SyntaxContext,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub mutbl: Mutability,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct TypeField {
- pub ident: Ident,
- pub mt: MutTy,
- pub span: Span,
-}
-
/// Represents a method's signature in a trait declaration,
/// or in an implementation.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum AsmDialect {
- AsmAtt,
- AsmIntel
+ Att,
+ Intel,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub items: Vec<P<ForeignItem>>,
}
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct VariantArg {
- pub ty: P<Ty>,
- pub id: NodeId,
-}
-
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum VariantKind {
- /// Tuple variant, e.g. `Foo(A, B)`
- TupleVariantKind(Vec<VariantArg>),
- /// Struct variant, e.g. `Foo {x: A, y: B}`
- StructVariantKind(P<StructDef>),
-}
-
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct EnumDef {
pub variants: Vec<P<Variant>>,
pub struct Variant_ {
pub name: Ident,
pub attrs: Vec<Attribute>,
- pub kind: VariantKind,
- pub id: NodeId,
+ pub data: VariantData,
/// Explicit discriminant, eg `Foo = 1`
pub disr_expr: Option<P<Expr>>,
- pub vis: Visibility,
}
pub type Variant = Spanned<Variant_>;
}
}
+ pub fn name(&self) -> Option<Ident> {
+ match *self {
+ PathListIdent { name, .. } => Some(name),
+ PathListMod { .. } => None,
+ }
+ }
+
pub fn rename(&self) -> Option<Ident> {
match *self {
PathListIdent { rename, .. } | PathListMod { rename, .. } => rename
/// distinguished for pretty-printing.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum AttrStyle {
- AttrOuter,
- AttrInner,
+ Outer,
+ Inner,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
}
}
+/// Fields and Ids of enum variants and structs
+///
+/// For enum variants: `NodeId` represents both an Id of the variant itself (relevant for all
+/// variant kinds) and an Id of the variant's constructor (not relevant for `Struct`-variants).
+/// One shared Id can be successfully used for these two purposes.
+/// Id of the whole enum lives in `Item`.
+///
+/// For structs: `NodeId` represents an Id of the structure's constructor, so it is not actually
+/// used for `Struct`-structs (but still presents). Structures don't have an analogue of "Id of
+/// the variant itself" from enum variants.
+/// Id of the whole struct lives in `Item`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct StructDef {
- /// Fields, not including ctor
- pub fields: Vec<StructField>,
- /// ID of the constructor. This is only used for tuple- or enum-like
- /// structs.
- pub ctor_id: Option<NodeId>,
+pub enum VariantData {
+ Struct(Vec<StructField>, NodeId),
+ Tuple(Vec<StructField>, NodeId),
+ Unit(NodeId),
+}
+
+impl VariantData {
+ pub fn fields(&self) -> &[StructField] {
+ match *self {
+ VariantData::Struct(ref fields, _) | VariantData::Tuple(ref fields, _) => fields,
+ _ => &[],
+ }
+ }
+ pub fn id(&self) -> NodeId {
+ match *self {
+ VariantData::Struct(_, id) | VariantData::Tuple(_, id) | VariantData::Unit(id) => id
+ }
+ }
+ pub fn is_struct(&self) -> bool {
+ if let VariantData::Struct(..) = *self { true } else { false }
+ }
+ pub fn is_tuple(&self) -> bool {
+ if let VariantData::Tuple(..) = *self { true } else { false }
+ }
+ pub fn is_unit(&self) -> bool {
+ if let VariantData::Unit(..) = *self { true } else { false }
+ }
}
/*
/// An enum definition, e.g. `enum Foo<A, B> {C<A>, D<B>}`
ItemEnum(EnumDef, Generics),
/// A struct definition, e.g. `struct Foo<A> {x: A}`
- ItemStruct(P<StructDef>, Generics),
+ ItemStruct(VariantData, Generics),
/// Represents a Trait Declaration
ItemTrait(Unsafety,
Generics,
idents.iter().map(|i| i.to_string()).collect::<Vec<String>>().join("::")
}
-pub fn stmt_id(s: &Stmt) -> NodeId {
+pub fn stmt_id(s: &Stmt) -> Option<NodeId> {
match s.node {
- StmtDecl(_, id) => id,
- StmtExpr(_, id) => id,
- StmtSemi(_, id) => id,
- StmtMac(..) => panic!("attempted to analyze unexpanded stmt")
+ StmtDecl(_, id) => Some(id),
+ StmtExpr(_, id) => Some(id),
+ StmtSemi(_, id) => Some(id),
+ StmtMac(..) => None,
}
}
pub fn unop_to_string(op: UnOp) -> &'static str {
match op {
- UnUniq => "box() ",
- UnDeref => "*",
- UnNot => "!",
- UnNeg => "-",
+ UnDeref => "*",
+ UnNot => "!",
+ UnNeg => "-",
}
}
}
}
}
- ItemEnum(ref enum_definition, _) => {
- for variant in &enum_definition.variants {
- self.operation.visit_id(variant.node.id)
- }
- }
_ => {}
}
}
fn visit_stmt(&mut self, statement: &Stmt) {
- self.operation.visit_id(ast_util::stmt_id(statement));
+ self.operation
+ .visit_id(ast_util::stmt_id(statement).expect("attempted to visit unexpanded stmt"));
visit::walk_stmt(self, statement)
}
visit::walk_struct_field(self, struct_field)
}
- fn visit_struct_def(&mut self,
- struct_def: &StructDef,
+ fn visit_variant_data(&mut self,
+ struct_def: &VariantData,
_: ast::Ident,
_: &ast::Generics,
- id: NodeId) {
- self.operation.visit_id(id);
- struct_def.ctor_id.map(|ctor_id| self.operation.visit_id(ctor_id));
+ _: NodeId,
+ _: Span) {
+ self.operation.visit_id(struct_def.id());
visit::walk_struct_def(self, struct_def);
}
visit::walk_impl_item(self, ii);
}
- fn visit_lifetime_ref(&mut self, lifetime: &Lifetime) {
+ fn visit_lifetime(&mut self, lifetime: &Lifetime) {
self.operation.visit_id(lifetime.id);
}
fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
- self.visit_lifetime_ref(&def.lifetime);
+ self.visit_lifetime(&def.lifetime);
}
fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
id_visitor.operation.result
}
-/// Returns true if the given struct def is tuple-like; i.e. that its fields
-/// are unnamed.
-pub fn struct_def_is_tuple_like(struct_def: &ast::StructDef) -> bool {
- struct_def.ctor_id.is_some()
-}
-
/// Returns true if the given pattern consists solely of an identifier
/// and false otherwise.
pub fn pat_is_ident(pat: P<ast::Pat>) -> bool {
use ast::*;
use super::*;
- fn ident_to_segment(id : &Ident) -> PathSegment {
- PathSegment {identifier: id.clone(),
+ fn ident_to_segment(id: Ident) -> PathSegment {
+ PathSegment {identifier: id,
parameters: PathParameters::none()}
}
#[test] fn idents_name_eq_test() {
assert!(segments_name_eq(
- &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>(),
- &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(78),ctxt:182}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()));
+ &[Ident::new(Name(3),SyntaxContext(4)), Ident::new(Name(78),SyntaxContext(82))]
+ .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>(),
+ &[Ident::new(Name(3),SyntaxContext(104)), Ident::new(Name(78),SyntaxContext(182))]
+ .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>()));
assert!(!segments_name_eq(
- &[Ident{name:Name(3),ctxt:4}, Ident{name:Name(78),ctxt:82}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>(),
- &[Ident{name:Name(3),ctxt:104}, Ident{name:Name(77),ctxt:182}]
- .iter().map(ident_to_segment).collect::<Vec<PathSegment>>()));
+ &[Ident::new(Name(3),SyntaxContext(4)), Ident::new(Name(78),SyntaxContext(82))]
+ .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>(),
+ &[Ident::new(Name(3),SyntaxContext(104)), Ident::new(Name(77),SyntaxContext(182))]
+ .iter().cloned().map(ident_to_segment).collect::<Vec<PathSegment>>()));
}
}
use std::cell::{RefCell, Cell};
use std::collections::HashSet;
-use std::fmt;
thread_local! {
static USED_ATTRS: RefCell<Vec<u64>> = RefCell::new(Vec::new())
InternedString::new("doc"),
token::intern_and_get_ident(&strip_doc_comment_decoration(
&comment)));
- if self.node.style == ast::AttrOuter {
+ if self.node.style == ast::AttrStyle::Outer {
f(&mk_attr_outer(self.node.id, meta))
} else {
f(&mk_attr_inner(self.node.id, meta))
pub fn mk_attr_inner(id: AttrId, item: P<MetaItem>) -> Attribute {
dummy_spanned(Attribute_ {
id: id,
- style: ast::AttrInner,
+ style: ast::AttrStyle::Inner,
value: item,
is_sugared_doc: false,
})
pub fn mk_attr_outer(id: AttrId, item: P<MetaItem>) -> Attribute {
dummy_spanned(Attribute_ {
id: id,
- style: ast::AttrOuter,
+ style: ast::AttrStyle::Outer,
value: item,
is_sugared_doc: false,
})
/// Determine what `#[inline]` attribute is present in `attrs`, if any.
pub fn find_inline_attr(diagnostic: Option<&SpanHandler>, attrs: &[Attribute]) -> InlineAttr {
- // FIXME (#2809)---validate the usage of #[inline] and #[inline]
attrs.iter().fold(InlineAttr::None, |ia,attr| {
match attr.node.value.node {
MetaWord(ref n) if *n == "inline" => {
}
}
-/// Represents the #[deprecated] and friends attributes.
+/// Represents the #[stable], #[unstable] and #[deprecated] attributes.
#[derive(RustcEncodable, RustcDecodable, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Stability {
pub level: StabilityLevel,
pub feature: InternedString,
- pub since: Option<InternedString>,
- pub deprecated_since: Option<InternedString>,
- // The reason for the current stability level. If deprecated, the
- // reason for deprecation.
- pub reason: Option<InternedString>,
- // The relevant rust-lang issue
- pub issue: Option<u32>
+ pub depr: Option<Deprecation>,
}
/// The available stability levels.
-#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Copy, Eq, Hash)]
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
pub enum StabilityLevel {
- Unstable,
- Stable,
+ // Reason for the current stability level and the relevant rust-lang issue
+ Unstable { reason: Option<InternedString>, issue: u32 },
+ Stable { since: InternedString },
}
-impl fmt::Display for StabilityLevel {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(self, f)
- }
+#[derive(RustcEncodable, RustcDecodable, PartialEq, PartialOrd, Clone, Debug, Eq, Hash)]
+pub struct Deprecation {
+ pub since: InternedString,
+ pub reason: InternedString,
}
-fn find_stability_generic<'a,
- AM: AttrMetaMethods,
- I: Iterator<Item=&'a AM>>
- (diagnostic: &SpanHandler, attrs: I, item_sp: Span)
- -> (Option<Stability>, Vec<&'a AM>) {
+impl StabilityLevel {
+ pub fn is_unstable(&self) -> bool { if let Unstable {..} = *self { true } else { false }}
+ pub fn is_stable(&self) -> bool { if let Stable {..} = *self { true } else { false }}
+}
+fn find_stability_generic<'a, I>(diagnostic: &SpanHandler,
+ attrs_iter: I,
+ item_sp: Span)
+ -> Option<Stability>
+ where I: Iterator<Item = &'a Attribute>
+{
let mut stab: Option<Stability> = None;
- let mut deprecated: Option<(Option<InternedString>, Option<InternedString>)> = None;
- let mut used_attrs: Vec<&'a AM> = vec![];
+ let mut depr: Option<Deprecation> = None;
- 'outer: for attr in attrs {
+ 'outer: for attr in attrs_iter {
let tag = attr.name();
- let tag = &tag[..];
+ let tag = &*tag;
if tag != "deprecated" && tag != "unstable" && tag != "stable" {
continue // not a stability level
}
- used_attrs.push(attr);
-
- let (feature, since, reason, issue) = match attr.meta_item_list() {
- Some(metas) => {
- let mut feature = None;
- let mut since = None;
- let mut reason = None;
- let mut issue = None;
- for meta in metas {
- match &*meta.name() {
- "feature" => {
- match meta.value_str() {
- Some(v) => feature = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
+ mark_used(attr);
+
+ if let Some(metas) = attr.meta_item_list() {
+ let get = |meta: &MetaItem, item: &mut Option<InternedString>| {
+ if item.is_some() {
+ diagnostic.span_err(meta.span, &format!("multiple '{}' items",
+ meta.name()));
+ return false
+ }
+ if let Some(v) = meta.value_str() {
+ *item = Some(v);
+ true
+ } else {
+ diagnostic.span_err(meta.span, "incorrect meta item");
+ false
+ }
+ };
+
+ match tag {
+ "deprecated" => {
+ if depr.is_some() {
+ diagnostic.span_err(item_sp, "multiple deprecated attributes");
+ break
+ }
+
+ let mut since = None;
+ let mut reason = None;
+ for meta in metas {
+ match &*meta.name() {
+ "since" => if !get(meta, &mut since) { continue 'outer },
+ "reason" => if !get(meta, &mut reason) { continue 'outer },
+ _ => {
+ diagnostic.span_err(meta.span, &format!("unknown meta item '{}'",
+ meta.name()));
+ continue 'outer
}
}
- "since" => {
- match meta.value_str() {
- Some(v) => since = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
- }
+ }
+
+ match (since, reason) {
+ (Some(since), Some(reason)) => {
+ depr = Some(Deprecation {
+ since: since,
+ reason: reason,
+ })
}
- "reason" => {
- match meta.value_str() {
- Some(v) => reason = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
- }
+ (None, _) => {
+ diagnostic.span_err(attr.span(), "missing 'since'");
+ continue
}
- "issue" => {
- match meta.value_str().and_then(|s| s.parse().ok()) {
- Some(v) => issue = Some(v),
- None => {
- diagnostic.span_err(meta.span, "incorrect meta item");
- continue 'outer;
- }
- }
+ _ => {
+ diagnostic.span_err(attr.span(), "missing 'reason'");
+ continue
}
- _ => {}
}
}
- (feature, since, reason, issue)
- }
- None => {
- diagnostic.span_err(attr.span(), "incorrect stability attribute type");
- continue
- }
- };
+ "unstable" => {
+ if stab.is_some() {
+ diagnostic.span_err(item_sp, "multiple stability levels");
+ break
+ }
- // Deprecated tags don't require feature names
- if feature == None && tag != "deprecated" {
- diagnostic.span_err(attr.span(), "missing 'feature'");
- }
+ let mut feature = None;
+ let mut reason = None;
+ let mut issue = None;
+ for meta in metas {
+ match &*meta.name() {
+ "feature" => if !get(meta, &mut feature) { continue 'outer },
+ "reason" => if !get(meta, &mut reason) { continue 'outer },
+ "issue" => if !get(meta, &mut issue) { continue 'outer },
+ _ => {
+ diagnostic.span_err(meta.span, &format!("unknown meta item '{}'",
+ meta.name()));
+ continue 'outer
+ }
+ }
+ }
- // Unstable tags don't require a version
- if since == None && tag != "unstable" {
- diagnostic.span_err(attr.span(), "missing 'since'");
- }
+ match (feature, reason, issue) {
+ (Some(feature), reason, Some(issue)) => {
+ stab = Some(Stability {
+ level: Unstable {
+ reason: reason,
+ issue: {
+ if let Ok(issue) = issue.parse() {
+ issue
+ } else {
+ diagnostic.span_err(attr.span(), "incorrect 'issue'");
+ continue
+ }
+ }
+ },
+ feature: feature,
+ depr: None,
+ })
+ }
+ (None, _, _) => {
+ diagnostic.span_err(attr.span(), "missing 'feature'");
+ continue
+ }
+ _ => {
+ diagnostic.span_err(attr.span(), "missing 'issue'");
+ continue
+ }
+ }
+ }
+ "stable" => {
+ if stab.is_some() {
+ diagnostic.span_err(item_sp, "multiple stability levels");
+ break
+ }
- if tag == "unstable" || tag == "stable" {
- if stab.is_some() {
- diagnostic.span_err(item_sp, "multiple stability levels");
- }
+ let mut feature = None;
+ let mut since = None;
+ for meta in metas {
+ match &*meta.name() {
+ "feature" => if !get(meta, &mut feature) { continue 'outer },
+ "since" => if !get(meta, &mut since) { continue 'outer },
+ _ => {
+ diagnostic.span_err(meta.span, &format!("unknown meta item '{}'",
+ meta.name()));
+ continue 'outer
+ }
+ }
+ }
- let level = match tag {
- "unstable" => Unstable,
- "stable" => Stable,
+ match (feature, since) {
+ (Some(feature), Some(since)) => {
+ stab = Some(Stability {
+ level: Stable {
+ since: since,
+ },
+ feature: feature,
+ depr: None,
+ })
+ }
+ (None, _) => {
+ diagnostic.span_err(attr.span(), "missing 'feature'");
+ continue
+ }
+ _ => {
+ diagnostic.span_err(attr.span(), "missing 'since'");
+ continue
+ }
+ }
+ }
_ => unreachable!()
- };
-
- stab = Some(Stability {
- level: level,
- feature: feature.unwrap_or(intern_and_get_ident("bogus")),
- since: since,
- deprecated_since: None,
- reason: reason,
- issue: issue,
- });
- } else { // "deprecated"
- if deprecated.is_some() {
- diagnostic.span_err(item_sp, "multiple deprecated attributes");
}
-
- deprecated = Some((since, reason));
+ } else {
+ diagnostic.span_err(attr.span(), "incorrect stability attribute type");
+ continue
}
}
// Merge the deprecation info into the stability info
- if deprecated.is_some() {
- match stab {
- Some(ref mut s) => {
- let (since, reason) = deprecated.unwrap();
- s.deprecated_since = since;
- s.reason = reason;
- }
- None => {
- diagnostic.span_err(item_sp, "deprecated attribute must be paired with \
- either stable or unstable attribute");
+ if let Some(depr) = depr {
+ if let Some(ref mut stab) = stab {
+ if let Unstable {reason: ref mut reason @ None, ..} = stab.level {
+ *reason = Some(depr.reason.clone())
}
+ stab.depr = Some(depr);
+ } else {
+ diagnostic.span_err(item_sp, "deprecated attribute must be paired with \
+ either stable or unstable attribute");
}
- } else if stab.as_ref().map_or(false, |s| s.level == Unstable && s.issue.is_none()) {
- // non-deprecated unstable items need to point to issues.
- diagnostic.span_err(item_sp,
- "non-deprecated unstable items need to point \
- to an issue with `issue = \"NNN\"`");
}
- (stab, used_attrs)
+ stab
}
/// Find the first stability attribute. `None` if none exists.
pub fn find_stability(diagnostic: &SpanHandler, attrs: &[Attribute],
item_sp: Span) -> Option<Stability> {
- let (s, used) = find_stability_generic(diagnostic, attrs.iter(), item_sp);
- for used in used { mark_used(used) }
- return s;
+ find_stability_generic(diagnostic, attrs.iter(), item_sp)
}
pub fn require_unique_names(diagnostic: &SpanHandler, metas: &[P<MetaItem>]) {
use serialize::{Encodable, Decodable, Encoder, Decoder};
-use parse::token::intern;
use ast::Name;
// _____________________________________________________________________________
pub fn substitute_dummy(self, other: Span) -> Span {
if self == DUMMY_SP { other } else { self }
}
+
+ pub fn contains(self, other: Span) -> bool {
+ self.lo <= other.lo && other.hi <= self.hi
+ }
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
MacroAttribute(Name),
/// e.g. `format!()`
MacroBang(Name),
- /// Syntax sugar expansion performed by the compiler (libsyntax::expand).
- CompilerExpansion(CompilerExpansionFormat),
-}
-
-#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq)]
-pub enum CompilerExpansionFormat {
- IfLet,
- PlacementIn,
- WhileLet,
- ForLoop,
}
-impl CompilerExpansionFormat {
- pub fn name(self) -> &'static str {
- match self {
- CompilerExpansionFormat::IfLet => "if let expansion",
- CompilerExpansionFormat::PlacementIn => "placement-in expansion",
- CompilerExpansionFormat::WhileLet => "while let expansion",
- CompilerExpansionFormat::ForLoop => "for loop expansion",
- }
- }
-}
#[derive(Clone, Hash, Debug)]
pub struct NameAndSpan {
/// The format with which the macro was invoked.
match self.format {
ExpnFormat::MacroAttribute(s) => s,
ExpnFormat::MacroBang(s) => s,
- ExpnFormat::CompilerExpansion(ce) => intern(ce.name()),
}
}
}
let span_comes_from_this_expansion =
info.callee.span.map_or(span == info.call_site, |mac_span| {
- mac_span.lo <= span.lo && span.hi <= mac_span.hi
+ mac_span.contains(span)
});
debug!("span_allows_unstable: span: {:?} call_site: {:?} callee: {:?}",
#[cfg(test)]
mod tests {
use super::*;
- use std::rc::Rc;
#[test]
fn t1 () {
if !(cx.in_cfg)(&v.node.attrs) {
None
} else {
- Some(v.map(|Spanned {node: ast::Variant_ {id, name, attrs, kind,
- disr_expr, vis}, span}| {
+ Some(v.map(|Spanned {node: ast::Variant_ {name, attrs, data,
+ disr_expr}, span}| {
Spanned {
node: ast::Variant_ {
- id: id,
name: name,
attrs: attrs,
- kind: match kind {
- ast::TupleVariantKind(..) => kind,
- ast::StructVariantKind(def) => {
- ast::StructVariantKind(fold_struct(cx, def))
- }
- },
+ data: fold_struct(cx, data),
disr_expr: disr_expr,
- vis: vis
},
span: span
}
fold::noop_fold_item_underscore(item, cx)
}
-fn fold_struct<F>(cx: &mut Context<F>, def: P<ast::StructDef>) -> P<ast::StructDef> where
+fn fold_struct<F>(cx: &mut Context<F>, vdata: ast::VariantData) -> ast::VariantData where
F: FnMut(&[ast::Attribute]) -> bool
{
- def.map(|ast::StructDef { fields, ctor_id }| {
- ast::StructDef {
- fields: fields.into_iter().filter(|m| {
+ match vdata {
+ ast::VariantData::Struct(fields, id) => {
+ ast::VariantData::Struct(fields.into_iter().filter(|m| {
(cx.in_cfg)(&m.node.attrs)
- }).collect(),
- ctor_id: ctor_id,
+ }).collect(), id)
}
- })
+ ast::VariantData::Tuple(fields, id) => {
+ ast::VariantData::Tuple(fields.into_iter().filter(|m| {
+ (cx.in_cfg)(&m.node.attrs)
+ }).collect(), id)
+ }
+ ast::VariantData::Unit(id) => ast::VariantData::Unit(id)
+ }
}
fn retain_stmt<F>(cx: &mut Context<F>, stmt: &ast::Stmt) -> bool where
fold::noop_fold_expr(ast::Expr {
id: id,
node: match node {
- ast::ExprMatch(m, arms, source) => {
+ ast::ExprMatch(m, arms) => {
ast::ExprMatch(m, arms.into_iter()
.filter(|a| (cx.in_cfg)(&a.attrs))
- .collect(), source)
+ .collect())
}
_ => node
},
let (pre, post) = match ei.callee.format {
codemap::MacroAttribute(..) => ("#[", "]"),
codemap::MacroBang(..) => ("", "!"),
- codemap::CompilerExpansion(..) => ("", ""),
};
// Don't print recursive invocations
if ei.call_site != last_span {
#[cfg(test)]
mod test {
use super::{EmitterWriter, Level};
- use codemap::{mk_sp, CodeMap, BytePos};
+ use codemap::{mk_sp, CodeMap};
use std::sync::{Arc, Mutex};
use std::io::{self, Write};
use std::str::from_utf8;
));
}
});
- let sym = Ident::new(token::gensym(&format!(
+ let sym = Ident::with_empty_ctxt(token::gensym(&format!(
"__register_diagnostic_{}", code
)));
MacEager::items(SmallVector::many(vec![
EntryPointType::Start
} else if attr::contains_name(&item.attrs, "main") {
EntryPointType::MainAttr
- } else if item.ident.name == "main" {
+ } else if item.ident.name.as_str() == "main" {
if depth == 1 {
// This is a top-level function so can be 'main'
EntryPointType::MainNamed
use parse::token::{intern, InternedString};
use parse::token;
use ptr::P;
+use syntax::ast::AsmDialect;
enum State {
Asm,
let mut clobs = Vec::new();
let mut volatile = false;
let mut alignstack = false;
- let mut dialect = ast::AsmAtt;
+ let mut dialect = AsmDialect::Att;
let mut state = Asm;
} else if option == "alignstack" {
alignstack = true;
} else if option == "intel" {
- dialect = ast::AsmIntel;
+ dialect = AsmDialect::Intel;
} else {
cx.span_warn(p.last_span, "unrecognized option");
}
use ast;
use ast::Name;
use codemap;
-use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION, CompilerExpansion};
+use codemap::{CodeMap, Span, ExpnId, ExpnInfo, NO_EXPANSION};
use ext;
use ext::expand;
use ext::tt::macro_rules;
syntax_expanders.insert(intern("cfg"),
builtin_normal_expander(
ext::cfg::expand_cfg));
- syntax_expanders.insert(intern("push_unsafe"),
- builtin_normal_expander(
- ext::pushpop_safe::expand_push_unsafe));
- syntax_expanders.insert(intern("pop_unsafe"),
- builtin_normal_expander(
- ext::pushpop_safe::expand_pop_unsafe));
syntax_expanders.insert(intern("trace_macros"),
builtin_normal_expander(
ext::trace_macros::expand_trace_macros));
}
}
- #[unstable(feature = "rustc_private")]
+ #[unstable(feature = "rustc_private", issue = "0")]
#[deprecated(since = "1.0.0",
reason = "Replaced with `expander().fold_expr()`")]
pub fn expand_expr(&mut self, e: P<ast::Expr>) -> P<ast::Expr> {
self.expander().fold_expr(e)
}
- /// Returns a `Folder` for deeply expanding all macros in a AST node.
+ /// Returns a `Folder` for deeply expanding all macros in an AST node.
pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
expand::MacroExpander::new(self)
}
loop {
if self.codemap().with_expn_info(expn_id, |info| {
info.map_or(None, |i| {
- if i.callee.name() == "include" {
+ if i.callee.name().as_str() == "include" {
// Stop going up the backtrace once include! is encountered
return None;
}
expn_id = i.call_site.expn_id;
- match i.callee.format {
- CompilerExpansion(..) => (),
- _ => last_macro = Some(i.call_site),
- }
+ last_macro = Some(i.call_site);
return Some(());
})
}).is_none() {
unreachable!()
}
- pub fn find(&self, k: &Name) -> Option<Rc<SyntaxExtension>> {
+ pub fn find(&self, k: Name) -> Option<Rc<SyntaxExtension>> {
for frame in self.chain.iter().rev() {
- match frame.map.get(k) {
+ match frame.map.get(&k) {
Some(v) => return Some(v.clone()),
None => {}
}
fn ty_vars(&self, ty_params: &OwnedSlice<ast::TyParam>) -> Vec<P<ast::Ty>> ;
fn ty_vars_global(&self, ty_params: &OwnedSlice<ast::TyParam>) -> Vec<P<ast::Ty>> ;
- fn ty_field_imm(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::TypeField;
fn typaram(&self,
span: Span,
fn item_struct_poly(&self,
span: Span,
name: Ident,
- struct_def: ast::StructDef,
+ struct_def: ast::VariantData,
generics: Generics) -> P<ast::Item>;
- fn item_struct(&self, span: Span, name: Ident, struct_def: ast::StructDef) -> P<ast::Item>;
+ fn item_struct(&self, span: Span, name: Ident, struct_def: ast::VariantData) -> P<ast::Item>;
fn item_mod(&self, span: Span, inner_span: Span,
name: Ident, attrs: Vec<ast::Attribute>,
Vec::new()))
}
- fn ty_field_imm(&self, span: Span, name: Ident, ty: P<ast::Ty>) -> ast::TypeField {
- ast::TypeField {
- ident: name,
- mt: ast::MutTy { ty: ty, mutbl: ast::MutImmutable },
- span: span,
- }
- }
-
fn ty_infer(&self, span: Span) -> P<ast::Ty> {
self.ty(span, ast::TyInfer)
}
}
fn expr_match(&self, span: Span, arg: P<ast::Expr>, arms: Vec<ast::Arm>) -> P<Expr> {
- self.expr(span, ast::ExprMatch(arg, arms, ast::MatchSource::Normal))
+ self.expr(span, ast::ExprMatch(arg, arms))
}
fn expr_if(&self, span: Span, cond: P<ast::Expr>,
}
fn variant(&self, span: Span, name: Ident, tys: Vec<P<ast::Ty>> ) -> ast::Variant {
- let args = tys.into_iter().map(|ty| {
- ast::VariantArg { ty: ty, id: ast::DUMMY_NODE_ID }
+ let fields: Vec<_> = tys.into_iter().map(|ty| {
+ Spanned { span: ty.span, node: ast::StructField_ {
+ ty: ty,
+ kind: ast::UnnamedField(ast::Inherited),
+ attrs: Vec::new(),
+ id: ast::DUMMY_NODE_ID,
+ }}
}).collect();
+ let vdata = if fields.is_empty() {
+ ast::VariantData::Unit(ast::DUMMY_NODE_ID)
+ } else {
+ ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID)
+ };
+
respan(span,
ast::Variant_ {
name: name,
attrs: Vec::new(),
- kind: ast::TupleVariantKind(args),
- id: ast::DUMMY_NODE_ID,
+ data: vdata,
disr_expr: None,
- vis: ast::Public
})
}
}
fn item_struct(&self, span: Span, name: Ident,
- struct_def: ast::StructDef) -> P<ast::Item> {
+ struct_def: ast::VariantData) -> P<ast::Item> {
self.item_struct_poly(
span,
name,
}
fn item_struct_poly(&self, span: Span, name: Ident,
- struct_def: ast::StructDef, generics: Generics) -> P<ast::Item> {
- self.item(span, name, Vec::new(), ast::ItemStruct(P(struct_def), generics))
+ struct_def: ast::VariantData, generics: Generics) -> P<ast::Item> {
+ self.item(span, name, Vec::new(), ast::ItemStruct(struct_def, generics))
}
fn item_mod(&self, span: Span, inner_span: Span, name: Ident,
fn attribute(&self, sp: Span, mi: P<ast::MetaItem>) -> ast::Attribute {
respan(sp, ast::Attribute_ {
id: attr::mk_attr_id(),
- style: ast::AttrOuter,
+ style: ast::AttrStyle::Outer,
value: mi,
is_sugared_doc: false,
})
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ast;
+use ast::{MetaItem, Expr,};
+use codemap::Span;
+use ext::base::{ExtCtxt, Annotatable};
+use ext::build::AstBuilder;
+use ext::deriving::generic::*;
+use ext::deriving::generic::ty::*;
+use parse::token;
+use ptr::P;
+
+pub fn expand_deriving_debug(cx: &mut ExtCtxt,
+ span: Span,
+ mitem: &MetaItem,
+ item: &Annotatable,
+ push: &mut FnMut(Annotatable))
+{
+ // &mut ::std::fmt::Formatter
+ let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))),
+ Borrowed(None, ast::MutMutable));
+
+ let trait_def = TraitDef {
+ span: span,
+ attributes: Vec::new(),
+ path: path_std!(cx, core::fmt::Debug),
+ additional_bounds: Vec::new(),
+ generics: LifetimeBounds::empty(),
+ is_unsafe: false,
+ methods: vec![
+ MethodDef {
+ name: "fmt",
+ generics: LifetimeBounds::empty(),
+ explicit_self: borrowed_explicit_self(),
+ args: vec!(fmtr),
+ ret_ty: Literal(path_std!(cx, core::fmt::Result)),
+ attributes: Vec::new(),
+ is_unsafe: false,
+ combine_substructure: combine_substructure(Box::new(|a, b, c| {
+ show_substructure(a, b, c)
+ }))
+ }
+ ],
+ associated_types: Vec::new(),
+ };
+ trait_def.expand(cx, mitem, item, push)
+}
+
+/// We use the debug builders to do the heavy lifting here
+fn show_substructure(cx: &mut ExtCtxt, span: Span,
+ substr: &Substructure) -> P<Expr> {
+ // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
+ // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
+ // based on the "shape".
+ let ident = match *substr.fields {
+ Struct(_) => substr.type_ident,
+ EnumMatching(_, v, _) => v.node.name,
+ EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
+ cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
+ }
+ };
+
+ // We want to make sure we have the expn_id set so that we can use unstable methods
+ let span = Span { expn_id: cx.backtrace(), .. span };
+ let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(),
+ ast::StrStyle::CookedStr));
+ let mut expr = substr.nonself_args[0].clone();
+
+ match *substr.fields {
+ Struct(ref fields) | EnumMatching(_, _, ref fields) => {
+
+ if fields.is_empty() || fields[0].name.is_none() {
+ // tuple struct/"normal" variant
+ expr = cx.expr_method_call(span,
+ expr,
+ token::str_to_ident("debug_tuple"),
+ vec![name]);
+
+ for field in fields {
+ // Use double indirection to make sure this works for unsized types
+ let field = cx.expr_addr_of(field.span, field.self_.clone());
+ let field = cx.expr_addr_of(field.span, field);
+
+ expr = cx.expr_method_call(span,
+ expr,
+ token::str_to_ident("field"),
+ vec![field]);
+ }
+ } else {
+ // normal struct/struct variant
+ expr = cx.expr_method_call(span,
+ expr,
+ token::str_to_ident("debug_struct"),
+ vec![name]);
+
+ for field in fields {
+ let name = cx.expr_lit(field.span, ast::Lit_::LitStr(
+ field.name.unwrap().name.as_str(),
+ ast::StrStyle::CookedStr));
+
+ // Use double indirection to make sure this works for unsized types
+ let field = cx.expr_addr_of(field.span, field.self_.clone());
+ let field = cx.expr_addr_of(field.span, field);
+ expr = cx.expr_method_call(span,
+ expr,
+ token::str_to_ident("field"),
+ vec![name, field]);
+ }
+ }
+ }
+ _ => unreachable!()
+ }
+
+ cx.expr_method_call(span,
+ expr,
+ token::str_to_ident("finish"),
+ vec![])
+}
//! A static method on the types above would result in,
//!
//! ```{.text}
-//! StaticStruct(<ast::StructDef of A>, Named(vec![(<ident of x>, <span of x>)]))
+//! StaticStruct(<ast::VariantData of A>, Named(vec![(<ident of x>, <span of x>)]))
//!
-//! StaticStruct(<ast::StructDef of B>, Unnamed(vec![<span of x>]))
+//! StaticStruct(<ast::VariantData of B>, Unnamed(vec![<span of x>]))
//!
//! StaticEnum(<ast::EnumDef of C>,
//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of i32>])),
use abi::Abi;
use abi;
use ast;
-use ast::{EnumDef, Expr, Ident, Generics, StructDef};
+use ast::{EnumDef, Expr, Ident, Generics, VariantData};
use ast_util;
use attr;
use attr::AttrMetaMethods;
EnumNonMatchingCollapsed(Vec<Ident>, &'a [P<ast::Variant>], &'a [Ident]),
/// A static method where `Self` is a struct.
- StaticStruct(&'a ast::StructDef, StaticFields),
+ StaticStruct(&'a ast::VariantData, StaticFields),
/// A static method where `Self` is an enum.
StaticEnum(&'a ast::EnumDef, Vec<(Ident, Span, StaticFields)>),
}
let mut attrs = newitem.attrs.clone();
attrs.extend(item.attrs.iter().filter(|a| {
match &a.name()[..] {
- "allow" | "warn" | "deny" | "forbid" => true,
+ "allow" | "warn" | "deny" | "forbid" | "stable" | "unstable" => true,
_ => false,
}
}).cloned());
fn expand_struct_def(&self,
cx: &mut ExtCtxt,
- struct_def: &'a StructDef,
+ struct_def: &'a VariantData,
type_ident: Ident,
generics: &Generics) -> P<ast::Item> {
- let field_tys: Vec<P<ast::Ty>> = struct_def.fields.iter()
+ let field_tys: Vec<P<ast::Ty>> = struct_def.fields().iter()
.map(|field| field.node.ty.clone())
.collect();
let mut field_tys = Vec::new();
for variant in &enum_def.variants {
- match variant.node.kind {
- ast::VariantKind::TupleVariantKind(ref args) => {
- field_tys.extend(args.iter()
- .map(|arg| arg.ty.clone()));
- }
- ast::VariantKind::StructVariantKind(ref args) => {
- field_tys.extend(args.fields.iter()
- .map(|field| field.node.ty.clone()));
- }
- }
+ field_tys.extend(variant.node.data.fields().iter()
+ .map(|field| field.node.ty.clone()));
}
let methods = self.methods.iter().map(|method_def| {
fn expand_struct_method_body<'b>(&self,
cx: &mut ExtCtxt,
trait_: &TraitDef<'b>,
- struct_def: &'b StructDef,
+ struct_def: &'b VariantData,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>])
fn expand_static_struct_method_body(&self,
cx: &mut ExtCtxt,
trait_: &TraitDef,
- struct_def: &StructDef,
+ struct_def: &VariantData,
type_ident: Ident,
self_args: &[P<Expr>],
nonself_args: &[P<Expr>])
-> P<Expr> {
let summary = enum_def.variants.iter().map(|v| {
let ident = v.node.name;
- let summary = match v.node.kind {
- ast::TupleVariantKind(ref args) => {
- Unnamed(args.iter().map(|va| trait_.set_expn_info(cx, va.ty.span)).collect())
- }
- ast::StructVariantKind(ref struct_def) => {
- trait_.summarise_struct(cx, &**struct_def)
- }
- };
+ let summary = trait_.summarise_struct(cx, &v.node.data);
(ident, v.span, summary)
}).collect();
self.call_substructure_method(cx, trait_, type_ident,
fn summarise_struct(&self,
cx: &mut ExtCtxt,
- struct_def: &StructDef) -> StaticFields {
+ struct_def: &VariantData) -> StaticFields {
let mut named_idents = Vec::new();
let mut just_spans = Vec::new();
- for field in struct_def.fields.iter(){
+ for field in struct_def.fields(){
let sp = self.set_expn_info(cx, field.span);
match field.node.kind {
ast::NamedField(ident, _) => named_idents.push((ident, sp)),
fn create_struct_pattern(&self,
cx: &mut ExtCtxt,
struct_path: ast::Path,
- struct_def: &'a StructDef,
+ struct_def: &'a VariantData,
prefix: &str,
mutbl: ast::Mutability)
-> (P<ast::Pat>, Vec<(Span, Option<Ident>,
P<Expr>,
&'a [ast::Attribute])>) {
- if struct_def.fields.is_empty() {
+ if struct_def.fields().is_empty() {
return (cx.pat_enum(self.span, struct_path, vec![]), vec![]);
}
let mut ident_expr = Vec::new();
let mut struct_type = Unknown;
- for (i, struct_field) in struct_def.fields.iter().enumerate() {
+ for (i, struct_field) in struct_def.fields().iter().enumerate() {
let sp = self.set_expn_info(cx, struct_field.span);
let opt_id = match struct_field.node.kind {
ast::NamedField(ident, _) if (struct_type == Unknown ||
-> (P<ast::Pat>, Vec<(Span, Option<Ident>, P<Expr>, &'a [ast::Attribute])>) {
let variant_ident = variant.node.name;
let variant_path = cx.path(variant.span, vec![enum_ident, variant_ident]);
- match variant.node.kind {
- ast::TupleVariantKind(ref variant_args) => {
- if variant_args.is_empty() {
- return (cx.pat_enum(variant.span, variant_path, vec![]), vec![]);
- }
-
- let mut paths = Vec::new();
- let mut ident_expr: Vec<(_, _, _, &'a [ast::Attribute])> = Vec::new();
- for (i, va) in variant_args.iter().enumerate() {
- let sp = self.set_expn_info(cx, va.ty.span);
- let ident = cx.ident_of(&format!("{}_{}", prefix, i));
- let path1 = codemap::Spanned{span: sp, node: ident};
- paths.push(path1);
- let expr_path = cx.expr_path(cx.path_ident(sp, ident));
- let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
- ident_expr.push((sp, None, val, &[]));
- }
-
- let subpats = self.create_subpatterns(cx, paths, mutbl);
-
- (cx.pat_enum(variant.span, variant_path, subpats),
- ident_expr)
- }
- ast::StructVariantKind(ref struct_def) => {
- self.create_struct_pattern(cx, variant_path, &**struct_def,
- prefix, mutbl)
- }
- }
+ self.create_struct_pattern(cx, variant_path, &variant.node.data, prefix, mutbl)
}
}
pub mod encodable;
pub mod decodable;
pub mod hash;
-pub mod show;
+pub mod debug;
pub mod default;
pub mod primitive;
"PartialOrd" => partial_ord::expand_deriving_partial_ord,
"Ord" => ord::expand_deriving_ord,
- "Debug" => show::expand_deriving_show,
+ "Debug" => debug::expand_deriving_debug,
"Default" => default::expand_deriving_default,
"Copy" => bounds::expand_deriving_copy,
// deprecated
- "Show" => show::expand_deriving_show,
"Encodable" => encodable::expand_deriving_encodable,
"Decodable" => decodable::expand_deriving_decodable,
}
#[inline] // because `name` is a compile-time constant
fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) {
if let Some(replacement) = match name {
- "Show" => Some("Debug"),
"Encodable" => Some("RustcEncodable"),
"Decodable" => Some("RustcDecodable"),
_ => None,
let mut arms = Vec::new();
for variant in &enum_def.variants {
- match variant.node.kind {
- ast::TupleVariantKind(ref args) => {
- if !args.is_empty() {
- cx.span_err(trait_span,
- "`FromPrimitive` cannot be derived for \
- enum variants with arguments");
- return cx.expr_fail(trait_span,
- InternedString::new(""));
- }
- let span = variant.span;
+ let def = &variant.node.data;
+ if !def.is_unit() {
+ cx.span_err(trait_span, "`FromPrimitive` cannot be derived \
+ for enums with non-unit variants");
+ return cx.expr_fail(trait_span,
+ InternedString::new(""));
+ }
- // expr for `$n == $variant as $name`
- let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
- let variant = cx.expr_path(path);
- let ty = cx.ty_ident(span, cx.ident_of(name));
- let cast = cx.expr_cast(span, variant.clone(), ty);
- let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
+ let span = variant.span;
- // expr for `Some($variant)`
- let body = cx.expr_some(span, variant);
+ // expr for `$n == $variant as $name`
+ let path = cx.path(span, vec![substr.type_ident, variant.node.name]);
+ let variant = cx.expr_path(path);
+ let ty = cx.ty_ident(span, cx.ident_of(name));
+ let cast = cx.expr_cast(span, variant.clone(), ty);
+ let guard = cx.expr_binary(span, ast::BiEq, n.clone(), cast);
- // arm for `_ if $guard => $body`
- let arm = ast::Arm {
- attrs: vec!(),
- pats: vec!(cx.pat_wild(span)),
- guard: Some(guard),
- body: body,
- };
+ // expr for `Some($variant)`
+ let body = cx.expr_some(span, variant);
- arms.push(arm);
- }
- ast::StructVariantKind(_) => {
- cx.span_err(trait_span,
- "`FromPrimitive` cannot be derived for enums \
- with struct variants");
- return cx.expr_fail(trait_span,
- InternedString::new(""));
- }
- }
+ // arm for `_ if $guard => $body`
+ let arm = ast::Arm {
+ attrs: vec!(),
+ pats: vec!(cx.pat_wild(span)),
+ guard: Some(guard),
+ body: body,
+ };
+
+ arms.push(arm);
}
// arm for `_ => None`
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use ast;
-use ast::{MetaItem, Expr,};
-use codemap::Span;
-use ext::base::{ExtCtxt, Annotatable};
-use ext::build::AstBuilder;
-use ext::deriving::generic::*;
-use ext::deriving::generic::ty::*;
-use parse::token;
-use ptr::P;
-
-pub fn expand_deriving_show(cx: &mut ExtCtxt,
- span: Span,
- mitem: &MetaItem,
- item: &Annotatable,
- push: &mut FnMut(Annotatable))
-{
- // &mut ::std::fmt::Formatter
- let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))),
- Borrowed(None, ast::MutMutable));
-
- let trait_def = TraitDef {
- span: span,
- attributes: Vec::new(),
- path: path_std!(cx, core::fmt::Debug),
- additional_bounds: Vec::new(),
- generics: LifetimeBounds::empty(),
- is_unsafe: false,
- methods: vec![
- MethodDef {
- name: "fmt",
- generics: LifetimeBounds::empty(),
- explicit_self: borrowed_explicit_self(),
- args: vec!(fmtr),
- ret_ty: Literal(path_std!(cx, core::fmt::Result)),
- attributes: Vec::new(),
- is_unsafe: false,
- combine_substructure: combine_substructure(Box::new(|a, b, c| {
- show_substructure(a, b, c)
- }))
- }
- ],
- associated_types: Vec::new(),
- };
- trait_def.expand(cx, mitem, item, push)
-}
-
-/// We use the debug builders to do the heavy lifting here
-fn show_substructure(cx: &mut ExtCtxt, span: Span,
- substr: &Substructure) -> P<Expr> {
- // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
- // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
- // based on the "shape".
- let ident = match *substr.fields {
- Struct(_) => substr.type_ident,
- EnumMatching(_, v, _) => v.node.name,
- EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
- cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
- }
- };
-
- // We want to make sure we have the expn_id set so that we can use unstable methods
- let span = Span { expn_id: cx.backtrace(), .. span };
- let name = cx.expr_lit(span, ast::Lit_::LitStr(ident.name.as_str(),
- ast::StrStyle::CookedStr));
- let mut expr = substr.nonself_args[0].clone();
-
- match *substr.fields {
- Struct(ref fields) | EnumMatching(_, _, ref fields) => {
-
- if fields.is_empty() || fields[0].name.is_none() {
- // tuple struct/"normal" variant
- expr = cx.expr_method_call(span,
- expr,
- token::str_to_ident("debug_tuple"),
- vec![name]);
-
- for field in fields {
- // Use double indirection to make sure this works for unsized types
- let field = cx.expr_addr_of(field.span, field.self_.clone());
- let field = cx.expr_addr_of(field.span, field);
-
- expr = cx.expr_method_call(span,
- expr,
- token::str_to_ident("field"),
- vec![field]);
- }
- } else {
- // normal struct/struct variant
- expr = cx.expr_method_call(span,
- expr,
- token::str_to_ident("debug_struct"),
- vec![name]);
-
- for field in fields {
- let name = cx.expr_lit(field.span, ast::Lit_::LitStr(
- field.name.unwrap().name.as_str(),
- ast::StrStyle::CookedStr));
-
- // Use double indirection to make sure this works for unsized types
- let field = cx.expr_addr_of(field.span, field.self_.clone());
- let field = cx.expr_addr_of(field.span, field);
- expr = cx.expr_method_call(span,
- expr,
- token::str_to_ident("field"),
- vec![name, field]);
- }
- }
- }
- _ => unreachable!()
- }
-
- cx.expr_method_call(span,
- expr,
- token::str_to_ident("finish"),
- vec![])
-}
// except according to those terms.
use ast::{Block, Crate, DeclLocal, ExprMac, PatMac};
-use ast::{Local, Ident, MacInvocTT};
+use ast::{Local, Ident, Mac_};
use ast::{ItemMac, MacStmtWithSemicolon, Mrk, Stmt, StmtDecl, StmtMac};
use ast::{StmtExpr, StmtSemi};
use ast::TokenTree;
use attr::AttrMetaMethods;
use codemap;
use codemap::{Span, Spanned, ExpnInfo, NameAndSpan, MacroBang, MacroAttribute};
-use codemap::{CompilerExpansion, CompilerExpansionFormat};
use ext::base::*;
use feature_gate::{self, Features, GatedCfg};
use fold;
use fold::*;
use parse;
use parse::token::{fresh_mark, fresh_name, intern};
-use parse::token;
use ptr::P;
use util::small_vector::SmallVector;
use visit;
use visit::Visitor;
use std_inject;
-// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
-// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
-fn mk_core_path(fld: &mut MacroExpander,
- span: Span,
- suffix: &[&'static str]) -> ast::Path {
- let idents = fld.cx.std_path(suffix);
- fld.cx.path_global(span, idents)
-}
pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
- fn push_compiler_expansion(fld: &mut MacroExpander, span: Span,
- expansion_type: CompilerExpansionFormat) {
- fld.cx.bt_push(ExpnInfo {
- call_site: span,
- callee: NameAndSpan {
- format: CompilerExpansion(expansion_type),
-
- // This does *not* mean code generated after
- // `push_compiler_expansion` is automatically exempt
- // from stability lints; must also tag such code with
- // an appropriate span from `fld.cx.backtrace()`.
- allow_internal_unstable: true,
-
- span: None,
- },
- });
- }
-
- // Sets the expn_id so that we can use unstable methods.
- fn allow_unstable(fld: &mut MacroExpander, span: Span) -> Span {
- Span { expn_id: fld.cx.backtrace(), ..span }
- }
-
let expr_span = e.span;
return e.and_then(|ast::Expr {id, node, span}| match node {
})
}
- // Desugar ExprBox: `in (PLACE) EXPR`
- ast::ExprBox(Some(placer), value_expr) => {
- // to:
- //
- // let p = PLACE;
- // let mut place = Placer::make_place(p);
- // let raw_place = Place::pointer(&mut place);
- // push_unsafe!({
- // std::intrinsics::move_val_init(raw_place, pop_unsafe!( EXPR ));
- // InPlace::finalize(place)
- // })
-
+ ast::ExprInPlace(placer, value_expr) => {
// Ensure feature-gate is enabled
feature_gate::check_for_placement_in(
fld.cx.ecfg.features,
&fld.cx.parse_sess.span_diagnostic,
expr_span);
- push_compiler_expansion(fld, expr_span, CompilerExpansionFormat::PlacementIn);
-
- let value_span = value_expr.span;
- let placer_span = placer.span;
-
- let placer_expr = fld.fold_expr(placer);
+ let placer = fld.fold_expr(placer);
let value_expr = fld.fold_expr(value_expr);
-
- let placer_ident = token::gensym_ident("placer");
- let agent_ident = token::gensym_ident("place");
- let p_ptr_ident = token::gensym_ident("p_ptr");
-
- let placer = fld.cx.expr_ident(span, placer_ident);
- let agent = fld.cx.expr_ident(span, agent_ident);
- let p_ptr = fld.cx.expr_ident(span, p_ptr_ident);
-
- let make_place = ["ops", "Placer", "make_place"];
- let place_pointer = ["ops", "Place", "pointer"];
- let move_val_init = ["intrinsics", "move_val_init"];
- let inplace_finalize = ["ops", "InPlace", "finalize"];
-
- let make_call = |fld: &mut MacroExpander, p, args| {
- // We feed in the `expr_span` because codemap's span_allows_unstable
- // allows the call_site span to inherit the `allow_internal_unstable`
- // setting.
- let span_unstable = allow_unstable(fld, expr_span);
- let path = mk_core_path(fld, span_unstable, p);
- let path = fld.cx.expr_path(path);
- let expr_span_unstable = allow_unstable(fld, span);
- fld.cx.expr_call(expr_span_unstable, path, args)
- };
-
- let stmt_let = |fld: &mut MacroExpander, bind, expr| {
- fld.cx.stmt_let(placer_span, false, bind, expr)
- };
- let stmt_let_mut = |fld: &mut MacroExpander, bind, expr| {
- fld.cx.stmt_let(placer_span, true, bind, expr)
- };
-
- // let placer = <placer_expr> ;
- let s1 = stmt_let(fld, placer_ident, placer_expr);
-
- // let mut place = Placer::make_place(placer);
- let s2 = {
- let call = make_call(fld, &make_place, vec![placer]);
- stmt_let_mut(fld, agent_ident, call)
- };
-
- // let p_ptr = Place::pointer(&mut place);
- let s3 = {
- let args = vec![fld.cx.expr_mut_addr_of(placer_span, agent.clone())];
- let call = make_call(fld, &place_pointer, args);
- stmt_let(fld, p_ptr_ident, call)
- };
-
- // pop_unsafe!(EXPR));
- let pop_unsafe_expr = pop_unsafe_expr(fld.cx, value_expr, value_span);
-
- // push_unsafe!({
- // ptr::write(p_ptr, pop_unsafe!(<value_expr>));
- // InPlace::finalize(place)
- // })
- let expr = {
- let call_move_val_init = StmtSemi(make_call(
- fld, &move_val_init, vec![p_ptr, pop_unsafe_expr]), ast::DUMMY_NODE_ID);
- let call_move_val_init = codemap::respan(value_span, call_move_val_init);
-
- let call = make_call(fld, &inplace_finalize, vec![agent]);
- Some(push_unsafe_expr(fld.cx, vec![P(call_move_val_init)], call, span))
- };
-
- let block = fld.cx.block_all(span, vec![s1, s2, s3], expr);
- let result = fld.cx.expr_block(block);
- fld.cx.bt_pop();
- result
+ fld.cx.expr(span, ast::ExprInPlace(placer, value_expr))
}
- // Issue #22181:
- // Eventually a desugaring for `box EXPR`
- // (similar to the desugaring above for `in PLACE BLOCK`)
- // should go here, desugaring
- //
- // to:
- //
- // let mut place = BoxPlace::make_place();
- // let raw_place = Place::pointer(&mut place);
- // let value = $value;
- // unsafe {
- // ::std::ptr::write(raw_place, value);
- // Boxed::finalize(place)
- // }
- //
- // But for now there are type-inference issues doing that.
-
ast::ExprWhile(cond, body, opt_ident) => {
let cond = fld.fold_expr(cond);
let (body, opt_ident) = expand_loop_block(body, opt_ident, fld);
fld.cx.expr(span, ast::ExprWhile(cond, body, opt_ident))
}
- // Desugar ExprWhileLet
- // From: `[opt_ident]: while let <pat> = <expr> <body>`
ast::ExprWhileLet(pat, expr, body, opt_ident) => {
- // to:
- //
- // [opt_ident]: loop {
- // match <expr> {
- // <pat> => <body>,
- // _ => break
- // }
- // }
-
- push_compiler_expansion(fld, span, CompilerExpansionFormat::WhileLet);
-
- // `<pat> => <body>`
- let pat_arm = {
- let body_expr = fld.cx.expr_block(body);
- fld.cx.arm(pat.span, vec![pat], body_expr)
- };
-
- // `_ => break`
- let break_arm = {
- let pat_under = fld.cx.pat_wild(span);
- let break_expr = fld.cx.expr_break(span);
- fld.cx.arm(span, vec![pat_under], break_expr)
- };
-
- // `match <expr> { ... }`
- let arms = vec![pat_arm, break_arm];
- let match_expr = fld.cx.expr(span,
- ast::ExprMatch(expr, arms, ast::MatchSource::WhileLetDesugar));
-
- // `[opt_ident]: loop { ... }`
- let loop_block = fld.cx.block_expr(match_expr);
- let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
- let result = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
- fld.cx.bt_pop();
- result
- }
-
- // Desugar ExprIfLet
- // From: `if let <pat> = <expr> <body> [<elseopt>]`
- ast::ExprIfLet(pat, expr, body, mut elseopt) => {
- // to:
- //
- // match <expr> {
- // <pat> => <body>,
- // [_ if <elseopt_if_cond> => <elseopt_if_body>,]
- // _ => [<elseopt> | ()]
- // }
-
- push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet);
-
- // `<pat> => <body>`
- let pat_arm = {
- let body_expr = fld.cx.expr_block(body);
- fld.cx.arm(pat.span, vec![pat], body_expr)
- };
-
- // `[_ if <elseopt_if_cond> => <elseopt_if_body>,]`
- let else_if_arms = {
- let mut arms = vec![];
- loop {
- let elseopt_continue = elseopt
- .and_then(|els| els.and_then(|els| match els.node {
- // else if
- ast::ExprIf(cond, then, elseopt) => {
- let pat_under = fld.cx.pat_wild(span);
- arms.push(ast::Arm {
- attrs: vec![],
- pats: vec![pat_under],
- guard: Some(cond),
- body: fld.cx.expr_block(then)
- });
- elseopt.map(|elseopt| (elseopt, true))
- }
- _ => Some((P(els), false))
- }));
- match elseopt_continue {
- Some((e, true)) => {
- elseopt = Some(e);
- }
- Some((e, false)) => {
- elseopt = Some(e);
- break;
- }
- None => {
- elseopt = None;
- break;
- }
- }
- }
- arms
- };
-
- let contains_else_clause = elseopt.is_some();
-
- // `_ => [<elseopt> | ()]`
- let else_arm = {
- let pat_under = fld.cx.pat_wild(span);
- let else_expr = elseopt.unwrap_or_else(|| fld.cx.expr_tuple(span, vec![]));
- fld.cx.arm(span, vec![pat_under], else_expr)
- };
-
- let mut arms = Vec::with_capacity(else_if_arms.len() + 2);
- arms.push(pat_arm);
- arms.extend(else_if_arms);
- arms.push(else_arm);
-
- let match_expr = fld.cx.expr(span,
- ast::ExprMatch(expr, arms,
- ast::MatchSource::IfLetDesugar {
- contains_else_clause: contains_else_clause,
- }));
- let result = fld.fold_expr(match_expr);
- fld.cx.bt_pop();
- result
- }
+ let pat = fld.fold_pat(pat);
+ let expr = fld.fold_expr(expr);
+
+ // Hygienic renaming of the body.
+ let ((body, opt_ident), mut rewritten_pats) =
+ rename_in_scope(vec![pat],
+ fld,
+ (body, opt_ident),
+ |rename_fld, fld, (body, opt_ident)| {
+ expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
+ });
+ assert!(rewritten_pats.len() == 1);
- // Desugar support for ExprIfLet in the ExprIf else position
- ast::ExprIf(cond, blk, elseopt) => {
- let elseopt = elseopt.map(|els| els.and_then(|els| match els.node {
- ast::ExprIfLet(..) => {
- push_compiler_expansion(fld, span, CompilerExpansionFormat::IfLet);
- // wrap the if-let expr in a block
- let span = els.span;
- let blk = P(ast::Block {
- stmts: vec![],
- expr: Some(P(els)),
- id: ast::DUMMY_NODE_ID,
- rules: ast::DefaultBlock,
- span: span
- });
- let result = fld.cx.expr_block(blk);
- fld.cx.bt_pop();
- result
- }
- _ => P(els)
- }));
- let if_expr = fld.cx.expr(span, ast::ExprIf(cond, blk, elseopt));
- if_expr.map(|e| noop_fold_expr(e, fld))
+ fld.cx.expr(span, ast::ExprWhileLet(rewritten_pats.remove(0), expr, body, opt_ident))
}
ast::ExprLoop(loop_block, opt_ident) => {
fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident))
}
- // Desugar ExprForLoop
- // From: `[opt_ident]: for <pat> in <head> <body>`
ast::ExprForLoop(pat, head, body, opt_ident) => {
- // to:
- //
- // {
- // let result = match ::std::iter::IntoIterator::into_iter(<head>) {
- // mut iter => {
- // [opt_ident]: loop {
- // match ::std::iter::Iterator::next(&mut iter) {
- // ::std::option::Option::Some(<pat>) => <body>,
- // ::std::option::Option::None => break
- // }
- // }
- // }
- // };
- // result
- // }
-
- push_compiler_expansion(fld, span, CompilerExpansionFormat::ForLoop);
-
- let span = fld.new_span(span);
+ let pat = fld.fold_pat(pat);
+
+ // Hygienic renaming of the for loop body (for loop binds its pattern).
+ let ((body, opt_ident), mut rewritten_pats) =
+ rename_in_scope(vec![pat],
+ fld,
+ (body, opt_ident),
+ |rename_fld, fld, (body, opt_ident)| {
+ expand_loop_block(rename_fld.fold_block(body), opt_ident, fld)
+ });
+ assert!(rewritten_pats.len() == 1);
- // expand <head>
let head = fld.fold_expr(head);
+ fld.cx.expr(span, ast::ExprForLoop(rewritten_pats.remove(0), head, body, opt_ident))
+ }
- let iter = token::gensym_ident("iter");
-
- let pat_span = fld.new_span(pat.span);
- // `::std::option::Option::Some(<pat>) => <body>`
- let pat_arm = {
- let body_expr = fld.cx.expr_block(body);
- let pat = fld.fold_pat(pat);
- let some_pat = fld.cx.pat_some(pat_span, pat);
-
- fld.cx.arm(pat_span, vec![some_pat], body_expr)
- };
-
- // `::std::option::Option::None => break`
- let break_arm = {
- let break_expr = fld.cx.expr_break(span);
-
- fld.cx.arm(span, vec![fld.cx.pat_none(span)], break_expr)
- };
-
- // `match ::std::iter::Iterator::next(&mut iter) { ... }`
- let match_expr = {
- let next_path = {
- let strs = fld.cx.std_path(&["iter", "Iterator", "next"]);
-
- fld.cx.path_global(span, strs)
- };
- let ref_mut_iter = fld.cx.expr_mut_addr_of(span, fld.cx.expr_ident(span, iter));
- let next_expr =
- fld.cx.expr_call(span, fld.cx.expr_path(next_path), vec![ref_mut_iter]);
- let arms = vec![pat_arm, break_arm];
-
- fld.cx.expr(pat_span,
- ast::ExprMatch(next_expr, arms, ast::MatchSource::ForLoopDesugar))
- };
-
- // `[opt_ident]: loop { ... }`
- let loop_block = fld.cx.block_expr(match_expr);
- let (loop_block, opt_ident) = expand_loop_block(loop_block, opt_ident, fld);
- let loop_expr = fld.cx.expr(span, ast::ExprLoop(loop_block, opt_ident));
-
- // `mut iter => { ... }`
- let iter_arm = {
- let iter_pat =
- fld.cx.pat_ident_binding_mode(span, iter, ast::BindByValue(ast::MutMutable));
- fld.cx.arm(span, vec![iter_pat], loop_expr)
- };
-
- // `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
- let into_iter_expr = {
- let into_iter_path = {
- let strs = fld.cx.std_path(&["iter", "IntoIterator",
- "into_iter"]);
-
- fld.cx.path_global(span, strs)
- };
+ ast::ExprIfLet(pat, sub_expr, body, else_opt) => {
+ let pat = fld.fold_pat(pat);
- fld.cx.expr_call(span, fld.cx.expr_path(into_iter_path), vec![head])
- };
-
- let match_expr = fld.cx.expr_match(span, into_iter_expr, vec![iter_arm]);
+ // Hygienic renaming of the body.
+ let (body, mut rewritten_pats) =
+ rename_in_scope(vec![pat],
+ fld,
+ body,
+ |rename_fld, fld, body| {
+ fld.fold_block(rename_fld.fold_block(body))
+ });
+ assert!(rewritten_pats.len() == 1);
- // `{ let result = ...; result }`
- let result_ident = token::gensym_ident("result");
- let result = fld.cx.expr_block(
- fld.cx.block_all(
- span,
- vec![fld.cx.stmt_let(span, false, result_ident, match_expr)],
- Some(fld.cx.expr_ident(span, result_ident))));
- fld.cx.bt_pop();
- result
+ let else_opt = else_opt.map(|else_opt| fld.fold_expr(else_opt));
+ let sub_expr = fld.fold_expr(sub_expr);
+ fld.cx.expr(span, ast::ExprIfLet(rewritten_pats.remove(0), sub_expr, body, else_opt))
}
ast::ExprClosure(capture_clause, fn_decl, block) => {
}, fld))
}
});
-
- fn push_unsafe_expr(cx: &mut ExtCtxt, stmts: Vec<P<ast::Stmt>>,
- expr: P<ast::Expr>, span: Span)
- -> P<ast::Expr> {
- let rules = ast::PushUnsafeBlock(ast::CompilerGenerated);
- cx.expr_block(P(ast::Block {
- rules: rules, span: span, id: ast::DUMMY_NODE_ID,
- stmts: stmts, expr: Some(expr),
- }))
- }
-
- fn pop_unsafe_expr(cx: &mut ExtCtxt, expr: P<ast::Expr>, span: Span)
- -> P<ast::Expr> {
- let rules = ast::PopUnsafeBlock(ast::CompilerGenerated);
- cx.expr_block(P(ast::Block {
- rules: rules, span: span, id: ast::DUMMY_NODE_ID,
- stmts: vec![], expr: Some(expr),
- }))
- }
}
/// Expand a (not-ident-style) macro invocation. Returns the result
F: for<'a> FnOnce(Box<MacResult+'a>) -> Option<T>,
G: FnOnce(T, Mrk) -> T,
{
- match mac.node {
- // it would almost certainly be cleaner to pass the whole
- // macro invocation in, rather than pulling it apart and
- // marking the tts and the ctxt separately. This also goes
- // for the other three macro invocation chunks of code
- // in this file.
- // Token-tree macros:
- MacInvocTT(pth, tts, _) => {
- if pth.segments.len() > 1 {
- fld.cx.span_err(pth.span,
- "expected macro name without module \
- separators");
- // let compilation continue
- return None;
- }
- let extname = pth.segments[0].identifier.name;
- match fld.cx.syntax_env.find(&extname) {
- None => {
- fld.cx.span_err(
- pth.span,
- &format!("macro undefined: '{}!'",
- &extname));
+ // it would almost certainly be cleaner to pass the whole
+ // macro invocation in, rather than pulling it apart and
+ // marking the tts and the ctxt separately. This also goes
+ // for the other three macro invocation chunks of code
+ // in this file.
+
+ let Mac_ { path: pth, tts, .. } = mac.node;
+ if pth.segments.len() > 1 {
+ fld.cx.span_err(pth.span,
+ "expected macro name without module \
+ separators");
+ // let compilation continue
+ return None;
+ }
+ let extname = pth.segments[0].identifier.name;
+ match fld.cx.syntax_env.find(extname) {
+ None => {
+ fld.cx.span_err(
+ pth.span,
+ &format!("macro undefined: '{}!'",
+ &extname));
- // let compilation continue
- None
- }
- Some(rc) => match *rc {
- NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
- fld.cx.bt_push(ExpnInfo {
- call_site: span,
- callee: NameAndSpan {
- format: MacroBang(extname),
- span: exp_span,
- allow_internal_unstable: allow_internal_unstable,
- },
- });
- let fm = fresh_mark();
- let marked_before = mark_tts(&tts[..], fm);
-
- // The span that we pass to the expanders we want to
- // be the root of the call stack. That's the most
- // relevant span and it's the actual invocation of
- // the macro.
- let mac_span = fld.cx.original_span();
-
- let opt_parsed = {
- let expanded = expandfun.expand(fld.cx,
- mac_span,
- &marked_before[..]);
- parse_thunk(expanded)
- };
- let parsed = match opt_parsed {
- Some(e) => e,
- None => {
- fld.cx.span_err(
- pth.span,
- &format!("non-expression macro in expression position: {}",
- extname
- ));
- return None;
- }
- };
- Some(mark_thunk(parsed,fm))
- }
- _ => {
+ // let compilation continue
+ None
+ }
+ Some(rc) => match *rc {
+ NormalTT(ref expandfun, exp_span, allow_internal_unstable) => {
+ fld.cx.bt_push(ExpnInfo {
+ call_site: span,
+ callee: NameAndSpan {
+ format: MacroBang(extname),
+ span: exp_span,
+ allow_internal_unstable: allow_internal_unstable,
+ },
+ });
+ let fm = fresh_mark();
+ let marked_before = mark_tts(&tts[..], fm);
+
+ // The span that we pass to the expanders we want to
+ // be the root of the call stack. That's the most
+ // relevant span and it's the actual invocation of
+ // the macro.
+ let mac_span = fld.cx.original_span();
+
+ let opt_parsed = {
+ let expanded = expandfun.expand(fld.cx,
+ mac_span,
+ &marked_before[..]);
+ parse_thunk(expanded)
+ };
+ let parsed = match opt_parsed {
+ Some(e) => e,
+ None => {
fld.cx.span_err(
pth.span,
- &format!("'{}' is not a tt-style macro",
- extname));
- None
+ &format!("non-expression macro in expression position: {}",
+ extname
+ ));
+ return None;
}
- }
+ };
+ Some(mark_thunk(parsed,fm))
+ }
+ _ => {
+ fld.cx.span_err(
+ pth.span,
+ &format!("'{}' is not a tt-style macro",
+ extname));
+ None
}
}
}
fld: &mut MacroExpander) -> (P<Block>, Option<Ident>) {
match opt_ident {
Some(label) => {
- let new_label = fresh_name(&label);
+ let new_label = fresh_name(label);
let rename = (label, new_label);
// The rename *must not* be added to the pending list of current
if attr.check_name("macro_escape") {
fld.cx.span_warn(attr.span, "macro_escape is a deprecated synonym for macro_use");
is_use = true;
- if let ast::AttrInner = attr.node.style {
+ if let ast::AttrStyle::Inner = attr.node.style {
fld.cx.fileline_help(attr.span, "consider an outer attribute, \
#[macro_use] mod ...");
}
// logic as for expression-position macro invocations.
pub fn expand_item_mac(it: P<ast::Item>,
fld: &mut MacroExpander) -> SmallVector<P<ast::Item>> {
- let (extname, path_span, tts) = match it.node {
- ItemMac(codemap::Spanned {
- node: MacInvocTT(ref pth, ref tts, _),
- ..
- }) => {
- (pth.segments[0].identifier.name, pth.span, (*tts).clone())
- }
+ let (extname, path_span, tts, span, attrs, ident) = it.and_then(|it| match it.node {
+ ItemMac(codemap::Spanned { node: Mac_ { path, tts, .. }, .. }) =>
+ (path.segments[0].identifier.name, path.span, tts, it.span, it.attrs, it.ident),
_ => fld.cx.span_bug(it.span, "invalid item macro invocation")
- };
+ });
let fm = fresh_mark();
let items = {
- let expanded = match fld.cx.syntax_env.find(&extname) {
+ let expanded = match fld.cx.syntax_env.find(extname) {
None => {
fld.cx.span_err(path_span,
&format!("macro undefined: '{}!'",
}
Some(rc) => match *rc {
- NormalTT(ref expander, span, allow_internal_unstable) => {
- if it.ident.name != parse::token::special_idents::invalid.name {
+ NormalTT(ref expander, tt_span, allow_internal_unstable) => {
+ if ident.name != parse::token::special_idents::invalid.name {
fld.cx
.span_err(path_span,
&format!("macro {}! expects no ident argument, given '{}'",
extname,
- it.ident));
+ ident));
return SmallVector::zero();
}
fld.cx.bt_push(ExpnInfo {
- call_site: it.span,
+ call_site: span,
callee: NameAndSpan {
format: MacroBang(extname),
- span: span,
+ span: tt_span,
allow_internal_unstable: allow_internal_unstable,
}
});
// mark before expansion:
let marked_before = mark_tts(&tts[..], fm);
- expander.expand(fld.cx, it.span, &marked_before[..])
+ expander.expand(fld.cx, span, &marked_before[..])
}
- IdentTT(ref expander, span, allow_internal_unstable) => {
- if it.ident.name == parse::token::special_idents::invalid.name {
+ IdentTT(ref expander, tt_span, allow_internal_unstable) => {
+ if ident.name == parse::token::special_idents::invalid.name {
fld.cx.span_err(path_span,
&format!("macro {}! expects an ident argument",
extname));
return SmallVector::zero();
}
fld.cx.bt_push(ExpnInfo {
- call_site: it.span,
+ call_site: span,
callee: NameAndSpan {
format: MacroBang(extname),
- span: span,
+ span: tt_span,
allow_internal_unstable: allow_internal_unstable,
}
});
// mark before expansion:
let marked_tts = mark_tts(&tts[..], fm);
- expander.expand(fld.cx, it.span, it.ident, marked_tts)
+ expander.expand(fld.cx, span, ident, marked_tts)
}
MacroRulesTT => {
- if it.ident.name == parse::token::special_idents::invalid.name {
+ if ident.name == parse::token::special_idents::invalid.name {
fld.cx.span_err(path_span,
&format!("macro_rules! expects an ident argument")
);
}
fld.cx.bt_push(ExpnInfo {
- call_site: it.span,
+ call_site: span,
callee: NameAndSpan {
format: MacroBang(extname),
span: None,
});
// DON'T mark before expansion.
- let allow_internal_unstable = attr::contains_name(&it.attrs,
+ let allow_internal_unstable = attr::contains_name(&attrs,
"allow_internal_unstable");
// ensure any #[allow_internal_unstable]s are
feature_gate::emit_feature_err(
&fld.cx.parse_sess.span_diagnostic,
"allow_internal_unstable",
- it.span,
+ span,
feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_ALLOW_INTERNAL_UNSTABLE)
}
+ let export = attr::contains_name(&attrs, "macro_export");
let def = ast::MacroDef {
- ident: it.ident,
- attrs: it.attrs.clone(),
+ ident: ident,
+ attrs: attrs,
id: ast::DUMMY_NODE_ID,
- span: it.span,
+ span: span,
imported_from: None,
- export: attr::contains_name(&it.attrs, "macro_export"),
+ export: export,
use_locally: true,
allow_internal_unstable: allow_internal_unstable,
body: tts,
return SmallVector::zero();
}
_ => {
- fld.cx.span_err(it.span,
+ fld.cx.span_err(span,
&format!("{}! is not legal in item position",
extname));
return SmallVector::zero();
// generate fresh names, push them to a new pending list
let idents = pattern_bindings(&*expanded_pat);
let mut new_pending_renames =
- idents.iter().map(|ident| (*ident, fresh_name(ident))).collect();
+ idents.iter().map(|ident| (*ident, fresh_name(*ident))).collect();
// rewrite the pattern using the new names (the old
// ones have already been applied):
let rewritten_pat = {
if expanded_pats.is_empty() {
panic!("encountered match arm with 0 patterns");
}
- // all of the pats must have the same set of bindings, so use the
- // first one to extract them and generate new names:
- let idents = pattern_bindings(&*expanded_pats[0]);
- let new_renames = idents.into_iter().map(|id| (id, fresh_name(&id))).collect();
- // apply the renaming, but only to the PatIdents:
- let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
- let rewritten_pats = expanded_pats.move_map(|pat| rename_pats_fld.fold_pat(pat));
+
// apply renaming and then expansion to the guard and the body:
- let mut rename_fld = IdentRenamer{renames:&new_renames};
- let rewritten_guard =
- arm.guard.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
- let rewritten_body = fld.fold_expr(rename_fld.fold_expr(arm.body));
+ let ((rewritten_guard, rewritten_body), rewritten_pats) =
+ rename_in_scope(expanded_pats,
+ fld,
+ (arm.guard, arm.body),
+ |rename_fld, fld, (ag, ab)|{
+ let rewritten_guard = ag.map(|g| fld.fold_expr(rename_fld.fold_expr(g)));
+ let rewritten_body = fld.fold_expr(rename_fld.fold_expr(ab));
+ (rewritten_guard, rewritten_body)
+ });
+
ast::Arm {
attrs: fold::fold_attrs(arm.attrs, fld),
pats: rewritten_pats,
}
}
+fn rename_in_scope<X, F>(pats: Vec<P<ast::Pat>>,
+ fld: &mut MacroExpander,
+ x: X,
+ f: F)
+ -> (X, Vec<P<ast::Pat>>)
+ where F: Fn(&mut IdentRenamer, &mut MacroExpander, X) -> X
+{
+ // all of the pats must have the same set of bindings, so use the
+ // first one to extract them and generate new names:
+ let idents = pattern_bindings(&*pats[0]);
+ let new_renames = idents.into_iter().map(|id| (id, fresh_name(id))).collect();
+ // apply the renaming, but only to the PatIdents:
+ let mut rename_pats_fld = PatIdentRenamer{renames:&new_renames};
+ let rewritten_pats = pats.move_map(|pat| rename_pats_fld.fold_pat(pat));
+
+ let mut rename_fld = IdentRenamer{ renames:&new_renames };
+ (f(&mut rename_fld, fld, x), rewritten_pats)
+}
+
/// A visitor that extracts the PatIdent (binding) paths
/// from a given thingy and puts them in a mutable
/// array
}
p.map(|ast::Pat {node, span, ..}| {
let (pth, tts) = match node {
- PatMac(mac) => match mac.node {
- MacInvocTT(pth, tts, _) => {
- (pth, tts)
- }
- },
+ PatMac(mac) => (mac.node.path, mac.node.tts),
_ => unreachable!()
};
if pth.segments.len() > 1 {
return DummyResult::raw_pat(span);
}
let extname = pth.segments[0].identifier.name;
- let marked_after = match fld.cx.syntax_env.find(&extname) {
+ let marked_after = match fld.cx.syntax_env.find(extname) {
None => {
fld.cx.span_err(pth.span,
&format!("macro undefined: '{}!'",
impl<'a> Folder for IdentRenamer<'a> {
fn fold_ident(&mut self, id: Ident) -> Ident {
- Ident {
- name: id.name,
- ctxt: mtwt::apply_renames(self.renames, id.ctxt),
- }
+ Ident::new(id.name, mtwt::apply_renames(self.renames, id.ctxt))
}
fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac {
fold::noop_fold_mac(mac, self)
pat.map(|ast::Pat {id, node, span}| match node {
ast::PatIdent(binding_mode, Spanned{span: sp, node: ident}, sub) => {
- let new_ident = Ident{name: ident.name,
- ctxt: mtwt::apply_renames(self.renames, ident.ctxt)};
+ let new_ident = Ident::new(ident.name,
+ mtwt::apply_renames(self.renames, ident.ctxt));
let new_node =
ast::PatIdent(binding_mode,
Spanned{span: self.new_span(sp), node: new_ident},
fld: &MacroExpander)
-> (Vec<ast::Attribute>, Vec<ast::Attribute>) {
attrs.iter().cloned().partition(|attr| {
- match fld.cx.syntax_env.find(&intern(&attr.name())) {
+ match fld.cx.syntax_env.find(intern(&attr.name())) {
Some(rc) => match *rc {
$variant(..) => true,
_ => false
{
for attr in a.attrs() {
let mname = intern(&attr.name());
- match fld.cx.syntax_env.find(&mname) {
+ match fld.cx.syntax_env.find(mname) {
Some(rc) => match *rc {
MultiDecorator(ref dec) => {
attr::mark_used(&attr);
for attr in &modifiers {
let mname = intern(&attr.name());
- match fld.cx.syntax_env.find(&mname) {
+ match fld.cx.syntax_env.find(mname) {
Some(rc) => match *rc {
MultiModifier(ref mac) => {
attr::mark_used(attr);
let expanded_decl = fld.fold_fn_decl(fn_decl);
let idents = fn_decl_arg_bindings(&*expanded_decl);
let renames =
- idents.iter().map(|id : &ast::Ident| (*id,fresh_name(id))).collect();
+ idents.iter().map(|id| (*id,fresh_name(*id))).collect();
// first, a renamer for the PatIdents, for the fn_decl:
let mut rename_pat_fld = PatIdentRenamer{renames: &renames};
let rewritten_fn_decl = rename_pat_fld.fold_fn_decl(expanded_decl);
impl Folder for Marker {
fn fold_ident(&mut self, id: Ident) -> Ident {
- ast::Ident {
- name: id.name,
- ctxt: mtwt::apply_mark(self.mark, id.ctxt)
- }
+ ast::Ident::new(id.name, mtwt::apply_mark(self.mark, id.ctxt))
}
fn fold_mac(&mut self, Spanned {node, span}: ast::Mac) -> ast::Mac {
Spanned {
- node: match node {
- MacInvocTT(path, tts, ctxt) => {
- MacInvocTT(self.fold_path(path),
- self.fold_tts(&tts[..]),
- mtwt::apply_mark(self.mark, ctxt))
- }
+ node: Mac_ {
+ path: self.fold_path(node.path),
+ tts: self.fold_tts(&node.tts),
+ ctxt: mtwt::apply_mark(self.mark, node.ctxt),
},
span: span,
}
// find the xx binding
let bindings = crate_bindings(&cr);
let cxbinds: Vec<&ast::Ident> =
- bindings.iter().filter(|b| b.name == "xx").collect();
+ bindings.iter().filter(|b| b.name.as_str() == "xx").collect();
let cxbinds: &[&ast::Ident] = &cxbinds[..];
let cxbind = match (cxbinds.len(), cxbinds.get(0)) {
(1, Some(b)) => *b,
// the xx binding should bind all of the xx varrefs:
for (idx,v) in varrefs.iter().filter(|p| {
p.segments.len() == 1
- && p.segments[0].identifier.name == "xx"
+ && p.segments[0].identifier.name.as_str() == "xx"
}).enumerate() {
if mtwt::resolve(v.segments[0].identifier) != resolved_binding {
println!("uh oh, xx binding didn't match xx varref:");
pub struct SCTable {
table: RefCell<Vec<SyntaxContext_>>,
mark_memo: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
- rename_memo: RefCell<HashMap<(SyntaxContext,Ident,Name),SyntaxContext>>,
+ // The pair (Name,SyntaxContext) is actually one Ident, but it needs to be hashed and
+ // compared as pair (name, ctxt) and not as an Ident
+ rename_memo: RefCell<HashMap<(SyntaxContext,(Name,SyntaxContext),Name),SyntaxContext>>,
}
#[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)]
/// Extend a syntax context with a given mark and sctable (explicit memoization)
fn apply_mark_internal(m: Mrk, ctxt: SyntaxContext, table: &SCTable) -> SyntaxContext {
let key = (ctxt, m);
- * table.mark_memo.borrow_mut().entry(key)
- .or_insert_with(|| idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt)))
+ *table.mark_memo.borrow_mut().entry(key).or_insert_with(|| {
+ SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Mark(m, ctxt)))
+ })
}
/// Extend a syntax context with a given rename
to: Name,
ctxt: SyntaxContext,
table: &SCTable) -> SyntaxContext {
- let key = (ctxt, id, to);
+ let key = (ctxt, (id.name, id.ctxt), to);
- * table.rename_memo.borrow_mut().entry(key)
- .or_insert_with(|| idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt)))
+ *table.rename_memo.borrow_mut().entry(key).or_insert_with(|| {
+ SyntaxContext(idx_push(&mut *table.table.borrow_mut(), Rename(id, to, ctxt)))
+ })
}
/// Apply a list of renamings to a context
}
let resolved = {
- let result = (*table.table.borrow())[id.ctxt as usize];
+ let result = (*table.table.borrow())[id.ctxt.0 as usize];
match result {
EmptyCtxt => id.name,
// ignore marks here:
Mark(_,subctxt) =>
- resolve_internal(Ident{name:id.name, ctxt: subctxt},
+ resolve_internal(Ident::new(id.name, subctxt),
table, resolve_table),
// do the rename if necessary:
Rename(Ident{name, ctxt}, toname, subctxt) => {
let resolvedfrom =
- resolve_internal(Ident{name:name, ctxt:ctxt},
+ resolve_internal(Ident::new(name, ctxt),
table, resolve_table);
let resolvedthis =
- resolve_internal(Ident{name:id.name, ctxt:subctxt},
+ resolve_internal(Ident::new(id.name, subctxt),
table, resolve_table);
if (resolvedthis == resolvedfrom)
&& (marksof_internal(ctxt, resolvedthis, table)
let mut result = Vec::new();
let mut loopvar = ctxt;
loop {
- let table_entry = (*table.table.borrow())[loopvar as usize];
+ let table_entry = (*table.table.borrow())[loopvar.0 as usize];
match table_entry {
EmptyCtxt => {
return result;
/// FAILS when outside is not a mark.
pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
with_sctable(|sctable| {
- match (*sctable.table.borrow())[ctxt as usize] {
+ match (*sctable.table.borrow())[ctxt.0 as usize] {
Mark(mrk, _) => mrk,
_ => panic!("can't retrieve outer mark when outside is not a mark")
}
}
fn id(n: u32, s: SyntaxContext) -> Ident {
- Ident {name: Name(n), ctxt: s}
+ Ident::new(Name(n), s)
}
// because of the SCTable, I now need a tidy way of
let mut result = Vec::new();
loop {
let table = table.table.borrow();
- match (*table)[sc as usize] {
+ match (*table)[sc.0 as usize] {
EmptyCtxt => {return result;},
Mark(mrk,tail) => {
result.push(M(mrk));
fn test_unfold_refold(){
let mut t = new_sctable_internal();
- let test_sc = vec!(M(3),R(id(101,0),Name(14)),M(9));
- assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),4);
+ let test_sc = vec!(M(3),R(id(101,EMPTY_CTXT),Name(14)),M(9));
+ assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),SyntaxContext(4));
{
let table = t.table.borrow();
- assert!((*table)[2] == Mark(9,0));
- assert!((*table)[3] == Rename(id(101,0),Name(14),2));
- assert!((*table)[4] == Mark(3,3));
+ assert!((*table)[2] == Mark(9,EMPTY_CTXT));
+ assert!((*table)[3] == Rename(id(101,EMPTY_CTXT),Name(14),SyntaxContext(2)));
+ assert!((*table)[4] == Mark(3,SyntaxContext(3)));
}
- assert_eq!(refold_test_sc(4,&t),test_sc);
+ assert_eq!(refold_test_sc(SyntaxContext(4),&t),test_sc);
}
// extend a syntax context with a sequence of marks given
#[test] fn unfold_marks_test() {
let mut t = new_sctable_internal();
- assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),3);
+ assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),SyntaxContext(3));
{
let table = t.table.borrow();
- assert!((*table)[2] == Mark(7,0));
- assert!((*table)[3] == Mark(3,2));
+ assert!((*table)[2] == Mark(7,EMPTY_CTXT));
+ assert!((*table)[3] == Mark(3,SyntaxContext(2)));
}
}
assert_eq! (marksof_internal (ans, stopname,&t), [16]);}
// rename where stop doesn't match:
{ let chain = vec!(M(9),
- R(id(name1.usize() as u32,
+ R(id(name1.0,
apply_mark_internal (4, EMPTY_CTXT,&mut t)),
Name(100101102)),
M(14));
// rename where stop does match
{ let name1sc = apply_mark_internal(4, EMPTY_CTXT, &mut t);
let chain = vec!(M(9),
- R(id(name1.usize() as u32, name1sc),
+ R(id(name1.0, name1sc),
stopname),
M(14));
let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
#[test]
fn hashing_tests () {
let mut t = new_sctable_internal();
- assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),2);
- assert_eq!(apply_mark_internal(13,EMPTY_CTXT,&mut t),3);
+ assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2));
+ assert_eq!(apply_mark_internal(13,EMPTY_CTXT,&mut t),SyntaxContext(3));
// using the same one again should result in the same index:
- assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),2);
+ assert_eq!(apply_mark_internal(12,EMPTY_CTXT,&mut t),SyntaxContext(2));
// I'm assuming that the rename table will behave the same....
}
#[test]
fn new_resolves_test() {
- let renames = vec!((Ident{name:Name(23),ctxt:EMPTY_CTXT},Name(24)),
- (Ident{name:Name(29),ctxt:EMPTY_CTXT},Name(29)));
+ let renames = vec!((Ident::with_empty_ctxt(Name(23)),Name(24)),
+ (Ident::with_empty_ctxt(Name(29)),Name(29)));
let new_ctxt1 = apply_renames(&renames,EMPTY_CTXT);
- assert_eq!(resolve(Ident{name:Name(23),ctxt:new_ctxt1}),Name(24));
- assert_eq!(resolve(Ident{name:Name(29),ctxt:new_ctxt1}),Name(29));
+ assert_eq!(resolve(Ident::new(Name(23),new_ctxt1)),Name(24));
+ assert_eq!(resolve(Ident::new(Name(29),new_ctxt1)),Name(29));
}
}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*
- * The compiler code necessary to support the `push_unsafe!` and
- * `pop_unsafe!` macros.
- *
- * This is a hack to allow a kind of "safety hygiene", where a macro
- * can generate code with an interior expression that inherits the
- * safety of some outer context.
- *
- * For example, in:
- *
- * ```rust
- * fn foo() { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) }
- * ```
- *
- * the `EXPR_1` is considered to be in an `unsafe` context,
- * but `EXPR_2` is considered to be in a "safe" (i.e. checked) context.
- *
- * For comparison, in:
- *
- * ```rust
- * fn foo() { unsafe { push_unsafe!( { EXPR_1; pop_unsafe!( EXPR_2 ) } ) } }
- * ```
- *
- * both `EXPR_1` and `EXPR_2` are considered to be in `unsafe`
- * contexts.
- *
- */
-
-use ast;
-use codemap::Span;
-use ext::base::*;
-use ext::base;
-use ext::build::AstBuilder;
-use feature_gate;
-use ptr::P;
-
-enum PushPop { Push, Pop }
-
-pub fn expand_push_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
- -> Box<base::MacResult+'cx> {
- expand_pushpop_unsafe(cx, sp, tts, PushPop::Push)
-}
-
-pub fn expand_pop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
- -> Box<base::MacResult+'cx> {
- expand_pushpop_unsafe(cx, sp, tts, PushPop::Pop)
-}
-
-fn expand_pushpop_unsafe<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree],
- pp: PushPop) -> Box<base::MacResult+'cx> {
- feature_gate::check_for_pushpop_syntax(
- cx.ecfg.features, &cx.parse_sess.span_diagnostic, sp);
-
- let mut exprs = match get_exprs_from_tts(cx, sp, tts) {
- Some(exprs) => exprs.into_iter(),
- None => return DummyResult::expr(sp),
- };
-
- let expr = match (exprs.next(), exprs.next()) {
- (Some(expr), None) => expr,
- _ => {
- let msg = match pp {
- PushPop::Push => "push_unsafe! takes 1 arguments",
- PushPop::Pop => "pop_unsafe! takes 1 arguments",
- };
- cx.span_err(sp, msg);
- return DummyResult::expr(sp);
- }
- };
-
- let source = ast::UnsafeSource::CompilerGenerated;
- let check_mode = match pp {
- PushPop::Push => ast::BlockCheckMode::PushUnsafeBlock(source),
- PushPop::Pop => ast::BlockCheckMode::PopUnsafeBlock(source),
- };
-
- MacEager::expr(cx.expr_block(P(ast::Block {
- stmts: vec![],
- expr: Some(expr),
- id: ast::DUMMY_NODE_ID,
- rules: check_mode,
- span: sp
- })))
-}
let mut r = vec![];
// FIXME: The spans could be better
r.push(ast::TtToken(self.span, token::Pound));
- if self.node.style == ast::AttrInner {
+ if self.node.style == ast::AttrStyle::Inner {
r.push(ast::TtToken(self.span, token::Not));
}
r.push(ast::TtDelimited(self.span, Rc::new(ast::Delimited {
($name: expr, $suffix: expr, $($args: expr),*) => {{
let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]);
let suffix = match $suffix {
- Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::new(name))),
+ Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))),
None => cx.expr_none(sp)
};
cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix])
}
token::Literal(token::Byte(i), suf) => {
- let e_byte = mk_name(cx, sp, i.ident());
+ let e_byte = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
return mk_lit!("Byte", suf, e_byte);
}
token::Literal(token::Char(i), suf) => {
- let e_char = mk_name(cx, sp, i.ident());
+ let e_char = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
return mk_lit!("Char", suf, e_char);
}
token::Literal(token::Integer(i), suf) => {
- let e_int = mk_name(cx, sp, i.ident());
+ let e_int = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i));
return mk_lit!("Integer", suf, e_int);
}
token::Literal(token::Float(fident), suf) => {
- let e_fident = mk_name(cx, sp, fident.ident());
+ let e_fident = mk_name(cx, sp, ast::Ident::with_empty_ctxt(fident));
return mk_lit!("Float", suf, e_fident);
}
token::Literal(token::Str_(ident), suf) => {
- return mk_lit!("Str_", suf, mk_name(cx, sp, ident.ident()))
+ return mk_lit!("Str_", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))
}
token::Literal(token::StrRaw(ident, n), suf) => {
- return mk_lit!("StrRaw", suf, mk_name(cx, sp, ident.ident()), cx.expr_usize(sp, n))
+ return mk_lit!("StrRaw", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)),
+ cx.expr_usize(sp, n))
}
token::Ident(ident, style) => {
token::DocComment(ident) => {
return cx.expr_call(sp,
mk_token_path(cx, sp, "DocComment"),
- vec!(mk_name(cx, sp, ident.ident())));
+ vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))));
}
token::MatchNt(name, kind, namep, kindp) => {
//! As it processes them, it fills up `eof_eis` with items that would be valid if
//! the macro invocation is now over, `bb_eis` with items that are waiting on
//! a Rust nonterminal like `$e:expr`, and `next_eis` with items that are waiting
-//! on the a particular token. Most of the logic concerns moving the · through the
+//! on a particular token. Most of the logic concerns moving the · through the
//! repetitions indicated by Kleene stars. It only advances or calls out to the
//! real Rust parser when no `cur_eis` items remain
//!
use self::TokenTreeOrTokenTreeVec::*;
use ast;
-use ast::{TokenTree, Ident};
+use ast::{TokenTree, Name};
use ast::{TtDelimited, TtSequence, TtToken};
use codemap::{BytePos, mk_sp, Span};
use codemap;
}
pub fn nameize(p_s: &ParseSess, ms: &[TokenTree], res: &[Rc<NamedMatch>])
- -> HashMap<Ident, Rc<NamedMatch>> {
+ -> HashMap<Name, Rc<NamedMatch>> {
fn n_rec(p_s: &ParseSess, m: &TokenTree, res: &[Rc<NamedMatch>],
- ret_val: &mut HashMap<Ident, Rc<NamedMatch>>, idx: &mut usize) {
+ ret_val: &mut HashMap<Name, Rc<NamedMatch>>, idx: &mut usize) {
match m {
&TtSequence(_, ref seq) => {
for next_m in &seq.tts {
}
}
&TtToken(sp, MatchNt(bind_name, _, _, _)) => {
- match ret_val.entry(bind_name) {
+ match ret_val.entry(bind_name.name) {
Vacant(spot) => {
spot.insert(res[*idx].clone());
*idx += 1;
Error(codemap::Span, String)
}
-pub type NamedParseResult = ParseResult<HashMap<Ident, Rc<NamedMatch>>>;
+pub type NamedParseResult = ParseResult<HashMap<Name, Rc<NamedMatch>>>;
pub type PositionalParseResult = ParseResult<Vec<Rc<NamedMatch>>>;
/// Perform a token equality check, ignoring syntax context (that is, an
};
// Extract the arguments:
- let lhses = match **argument_map.get(&lhs_nm).unwrap() {
+ let lhses = match **argument_map.get(&lhs_nm.name).unwrap() {
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
_ => cx.span_bug(def.span, "wrong-structured lhs")
};
check_lhs_nt_follows(cx, &**lhs, def.span);
}
- let rhses = match **argument_map.get(&rhs_nm).unwrap() {
+ let rhses = match **argument_map.get(&rhs_nm.name).unwrap() {
MatchedSeq(ref s, _) => /* FIXME (#2543) */ (*s).clone(),
_ => cx.span_bug(def.span, "wrong-structured rhs")
};
Ok(true)
},
"block" => {
- // anything can follow block, the braces provide a easy boundary to
+ // anything can follow block, the braces provide an easy boundary to
// maintain
Ok(true)
},
"pat" => {
match *tok {
FatArrow | Comma | Eq => Ok(true),
- Ident(i, _) if i.name == "if" || i.name == "in" => Ok(true),
+ Ident(i, _) if i.name.as_str() == "if" || i.name.as_str() == "in" => Ok(true),
_ => Ok(false)
}
},
"path" | "ty" => {
match *tok {
Comma | FatArrow | Colon | Eq | Gt | Semi => Ok(true),
- Ident(i, _) if i.name == "as" => Ok(true),
+ Ident(i, _) if i.name.as_str() == "as" => Ok(true),
_ => Ok(false)
}
},
use self::LockstepIterSize::*;
use ast;
-use ast::{TokenTree, TtDelimited, TtToken, TtSequence, Ident};
+use ast::{TokenTree, TtDelimited, TtToken, TtSequence, Ident, Name};
use codemap::{Span, DUMMY_SP};
use diagnostic::SpanHandler;
use ext::tt::macro_parser::{NamedMatch, MatchedSeq, MatchedNonterminal};
/// the unzipped tree:
stack: Vec<TtFrame>,
/* for MBE-style macro transcription */
- interpolations: HashMap<Ident, Rc<NamedMatch>>,
+ interpolations: HashMap<Name, Rc<NamedMatch>>,
imported_from: Option<Ident>,
// Some => return imported_from as the next token
/// `src` contains no `TtSequence`s, `MatchNt`s or `SubstNt`s, `interp` can
/// (and should) be None.
pub fn new_tt_reader<'a>(sp_diag: &'a SpanHandler,
- interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
+ interp: Option<HashMap<Name, Rc<NamedMatch>>>,
imported_from: Option<Ident>,
src: Vec<ast::TokenTree>)
-> TtReader<'a> {
/// `src` contains no `TtSequence`s, `MatchNt`s or `SubstNt`s, `interp` can
/// (and should) be None.
pub fn new_tt_reader_with_doc_flag<'a>(sp_diag: &'a SpanHandler,
- interp: Option<HashMap<Ident, Rc<NamedMatch>>>,
+ interp: Option<HashMap<Name, Rc<NamedMatch>>>,
imported_from: Option<Ident>,
src: Vec<ast::TokenTree>,
desugar_doc_comments: bool)
}
fn lookup_cur_matched(r: &TtReader, name: Ident) -> Option<Rc<NamedMatch>> {
- let matched_opt = r.interpolations.get(&name).cloned();
+ let matched_opt = r.interpolations.get(&name.name).cloned();
matched_opt.map(|s| lookup_cur_matched_by_matched(r, s))
}
use diagnostic::SpanHandler;
use visit;
use visit::{FnKind, Visitor};
-use parse::token::{self, InternedString};
+use parse::token::InternedString;
use std::ascii::AsciiExt;
use std::cmp;
("associated_types", "1.0.0", None, Accepted),
("visible_private_types", "1.0.0", None, Active),
("slicing_syntax", "1.0.0", None, Accepted),
- ("box_syntax", "1.0.0", None, Active),
- ("placement_in_syntax", "1.0.0", None, Active),
+ ("box_syntax", "1.0.0", Some(27779), Active),
+ ("placement_in_syntax", "1.0.0", Some(27779), Active),
("pushpop_unsafe", "1.2.0", None, Active),
("on_unimplemented", "1.0.0", None, Active),
("simd_ffi", "1.0.0", None, Active),
// switch to Accepted; see RFC 320)
("unsafe_no_drop_flag", "1.0.0", None, Active),
+ // Allows using the unsafe_destructor_blind_to_params attribute;
+ // RFC 1238
+ ("dropck_parametricity", "1.3.0", Some(28498), Active),
+
// Allows the use of custom attributes; RFC 572
("custom_attribute", "1.0.0", None, Active),
// allow `#[unwind]`
("unwind_attributes", "1.4.0", None, Active),
+
+ // allow empty structs and enum variants with braces
+ ("braced_empty_structs", "1.5.0", None, Active),
+
+ // allow overloading augmented assignment operations like `a += b`
+ ("augmented_assignments", "1.5.0", None, Active),
+
+ // allow `#[no_debug]`
+ ("no_debug", "1.5.0", None, Active),
+
+ // allow `#[omit_gdb_pretty_printer_section]`
+ ("omit_gdb_pretty_printer_section", "1.5.0", None, Active),
+
+ // Allows cfg(target_vendor = "...").
+ ("cfg_target_vendor", "1.5.0", None, Active),
];
// (changing above list without updating src/doc/reference.md makes @cmr sad)
("link_section", Whitelisted, Ungated),
("no_builtins", Whitelisted, Ungated),
("no_mangle", Whitelisted, Ungated),
- ("no_debug", Whitelisted, Ungated),
- ("omit_gdb_pretty_printer_section", Whitelisted, Ungated),
+ ("no_debug", Whitelisted, Gated("no_debug",
+ "the `#[no_debug]` attribute \
+ is an experimental feature")),
+ ("omit_gdb_pretty_printer_section", Whitelisted, Gated("omit_gdb_pretty_printer_section",
+ "the `#[omit_gdb_pretty_printer_section]` \
+ attribute is just used for the Rust test \
+ suite")),
("unsafe_no_drop_flag", Whitelisted, Gated("unsafe_no_drop_flag",
"unsafe_no_drop_flag has unstable semantics \
and may be removed in the future")),
+ ("unsafe_destructor_blind_to_params",
+ Normal,
+ Gated("dropck_parametricity",
+ "unsafe_destructor_blind_to_params has unstable semantics \
+ and may be removed in the future")),
("unwind", Whitelisted, Gated("unwind_attributes", "#[unwind] is experimental")),
// used in resolve
const GATED_CFGS: &'static [(&'static str, &'static str, fn(&Features) -> bool)] = &[
// (name in cfg, feature, function to check if the feature is enabled)
("target_feature", "cfg_target_feature", cfg_fn!(|x| x.cfg_target_feature)),
+ ("target_vendor", "cfg_target_vendor", cfg_fn!(|x| x.cfg_target_vendor)),
];
#[derive(Debug, Eq, PartialEq)]
pub default_type_parameter_fallback: bool,
pub type_macros: bool,
pub cfg_target_feature: bool,
+ pub cfg_target_vendor: bool,
+ pub augmented_assignments: bool,
+ pub braced_empty_structs: bool,
}
impl Features {
default_type_parameter_fallback: false,
type_macros: false,
cfg_target_feature: false,
+ cfg_target_vendor: false,
+ augmented_assignments: false,
+ braced_empty_structs: false,
}
}
}
impl<'a, 'v> Visitor<'v> for MacroVisitor<'a> {
fn visit_mac(&mut self, mac: &ast::Mac) {
- let ast::MacInvocTT(ref path, _, _) = mac.node;
- let id = path.segments.last().unwrap().identifier;
+ let path = &mac.node.path;
+ let name = path.segments.last().unwrap().identifier.name.as_str();
// Issue 22234: If you add a new case here, make sure to also
// add code to catch the macro during or after expansion.
// catch uses of these macros within conditionally-compiled
// code, e.g. `#[cfg]`-guarded functions.
- if id == token::str_to_ident("asm") {
+ if name == "asm" {
self.context.gate_feature("asm", path.span, EXPLAIN_ASM);
}
- else if id == token::str_to_ident("log_syntax") {
+ else if name == "log_syntax" {
self.context.gate_feature("log_syntax", path.span, EXPLAIN_LOG_SYNTAX);
}
- else if id == token::str_to_ident("trace_macros") {
+ else if name == "trace_macros" {
self.context.gate_feature("trace_macros", path.span, EXPLAIN_TRACE_MACROS);
}
- else if id == token::str_to_ident("concat_idents") {
+ else if name == "concat_idents" {
self.context.gate_feature("concat_idents", path.span, EXPLAIN_CONCAT_IDENTS);
}
}
// But we keep these checks as a pre-expansion check to catch
// uses in e.g. conditionalized code.
- if let ast::ExprBox(None, _) = e.node {
+ if let ast::ExprBox(_) = e.node {
self.context.gate_feature("box_syntax", e.span, EXPLAIN_BOX_SYNTAX);
}
- if let ast::ExprBox(Some(_), _) = e.node {
+ if let ast::ExprInPlace(..) = e.node {
self.context.gate_feature("placement_in_syntax", e.span, EXPLAIN_PLACEMENT_IN);
}
}
struct PostExpansionVisitor<'a> {
- context: &'a Context<'a>
+ context: &'a Context<'a>,
}
impl<'a> PostExpansionVisitor<'a> {
visit::walk_item(self, i);
}
+ fn visit_variant_data(&mut self, s: &'v ast::VariantData, _: ast::Ident,
+ _: &'v ast::Generics, _: ast::NodeId, span: Span) {
+ if s.fields().is_empty() {
+ if s.is_struct() {
+ self.gate_feature("braced_empty_structs", span,
+ "empty structs and enum variants with braces are unstable");
+ } else if s.is_tuple() {
+ self.context.span_handler.span_err(span, "empty tuple structs and enum variants \
+ are not allowed, use unit structs and \
+ enum variants instead");
+ }
+ }
+ visit::walk_struct_def(self, s)
+ }
+
fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
let links_to_llvm = match attr::first_attr_value_str_by_name(&i.attrs,
"link_name") {
fn visit_expr(&mut self, e: &ast::Expr) {
match e.node {
- ast::ExprBox(..) | ast::ExprUnary(ast::UnOp::UnUniq, _) => {
+ ast::ExprBox(_) => {
self.gate_feature("box_syntax",
e.span,
"box expression syntax is experimental; \
default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
type_macros: cx.has_feature("type_macros"),
cfg_target_feature: cx.has_feature("cfg_target_feature"),
+ cfg_target_vendor: cx.has_feature("cfg_target_vendor"),
+ augmented_assignments: cx.has_feature("augmented_assignments"),
+ braced_empty_structs: cx.has_feature("braced_empty_structs"),
}
}
/// Errors are bypassed for bootstrapping. This is required any time
/// during the build that feature-related lints are set to warn or above
/// because the build turns on warnings-as-errors and uses lots of unstable
- /// features. As a result, this this is always required for building Rust
- /// itself.
+ /// features. As a result, this is always required for building Rust itself.
Cheat
}
noop_fold_poly_trait_ref(p, self)
}
- fn fold_struct_def(&mut self, struct_def: P<StructDef>) -> P<StructDef> {
- noop_fold_struct_def(struct_def, self)
+ fn fold_variant_data(&mut self, vdata: VariantData) -> VariantData {
+ noop_fold_variant_data(vdata, self)
}
fn fold_lifetimes(&mut self, lts: Vec<Lifetime>) -> Vec<Lifetime> {
noop_fold_opt_lifetime(o_lt, self)
}
- fn fold_variant_arg(&mut self, va: VariantArg) -> VariantArg {
- noop_fold_variant_arg(va, self)
- }
-
fn fold_opt_bounds(&mut self, b: Option<OwnedSlice<TyParamBound>>)
-> Option<OwnedSlice<TyParamBound>> {
noop_fold_opt_bounds(b, self)
}
pub fn noop_fold_variant<T: Folder>(v: P<Variant>, fld: &mut T) -> P<Variant> {
- v.map(|Spanned {node: Variant_ {id, name, attrs, kind, disr_expr, vis}, span}| Spanned {
+ v.map(|Spanned {node: Variant_ {name, attrs, data, disr_expr}, span}| Spanned {
node: Variant_ {
- id: fld.new_id(id),
name: name,
attrs: fold_attrs(attrs, fld),
- kind: match kind {
- TupleVariantKind(variant_args) => {
- TupleVariantKind(variant_args.move_map(|x|
- fld.fold_variant_arg(x)))
- }
- StructVariantKind(struct_def) => {
- StructVariantKind(fld.fold_struct_def(struct_def))
- }
- },
+ data: fld.fold_variant_data(data),
disr_expr: disr_expr.map(|e| fld.fold_expr(e)),
- vis: vis,
},
span: fld.new_span(span),
})
pub fn noop_fold_mac<T: Folder>(Spanned {node, span}: Mac, fld: &mut T) -> Mac {
Spanned {
- node: match node {
- MacInvocTT(p, tts, ctxt) => {
- MacInvocTT(fld.fold_path(p), fld.fold_tts(&tts), ctxt)
- }
+ node: Mac_ {
+ path: fld.fold_path(node.path),
+ tts: fld.fold_tts(&node.tts),
+ ctxt: node.ctxt,
},
span: fld.new_span(span)
}
}
}
-pub fn noop_fold_struct_def<T: Folder>(struct_def: P<StructDef>, fld: &mut T) -> P<StructDef> {
- struct_def.map(|StructDef { fields, ctor_id }| StructDef {
- fields: fields.move_map(|f| fld.fold_struct_field(f)),
- ctor_id: ctor_id.map(|cid| fld.new_id(cid)),
- })
+pub fn noop_fold_variant_data<T: Folder>(vdata: VariantData, fld: &mut T) -> VariantData {
+ match vdata {
+ ast::VariantData::Struct(fields, id) => {
+ ast::VariantData::Struct(fields.move_map(|f| fld.fold_struct_field(f)),
+ fld.new_id(id))
+ }
+ ast::VariantData::Tuple(fields, id) => {
+ ast::VariantData::Tuple(fields.move_map(|f| fld.fold_struct_field(f)),
+ fld.new_id(id))
+ }
+ ast::VariantData::Unit(id) => ast::VariantData::Unit(fld.new_id(id))
+ }
}
pub fn noop_fold_trait_ref<T: Folder>(p: TraitRef, fld: &mut T) -> TraitRef {
bounds.move_map(|bound| folder.fold_ty_param_bound(bound))
}
-fn noop_fold_variant_arg<T: Folder>(VariantArg {id, ty}: VariantArg, folder: &mut T)
- -> VariantArg {
- VariantArg {
- id: folder.new_id(id),
- ty: folder.fold_ty(ty)
- }
-}
-
pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> {
b.map(|Block {id, stmts, expr, rules, span}| Block {
id: folder.new_id(id),
folder.fold_generics(generics))
}
ItemStruct(struct_def, generics) => {
- let struct_def = folder.fold_struct_def(struct_def);
+ let struct_def = folder.fold_variant_data(struct_def);
ItemStruct(struct_def, folder.fold_generics(generics))
}
ItemDefaultImpl(unsafety, ref trait_ref) => {
Expr {
id: folder.new_id(id),
node: match node {
- ExprBox(p, e) => {
- ExprBox(p.map(|e|folder.fold_expr(e)), folder.fold_expr(e))
+ ExprBox(e) => {
+ ExprBox(folder.fold_expr(e))
+ }
+ ExprInPlace(p, e) => {
+ ExprInPlace(folder.fold_expr(p), folder.fold_expr(e))
}
ExprVec(exprs) => {
ExprVec(exprs.move_map(|x| folder.fold_expr(x)))
ExprLoop(folder.fold_block(body),
opt_ident.map(|i| folder.fold_ident(i)))
}
- ExprMatch(expr, arms, source) => {
+ ExprMatch(expr, arms) => {
ExprMatch(folder.fold_expr(expr),
- arms.move_map(|x| folder.fold_arm(x)),
- source)
+ arms.move_map(|x| folder.fold_arm(x)))
}
ExprClosure(capture_clause, decl, body) => {
ExprClosure(capture_clause,
#![feature(drain)]
#![feature(filling_drop)]
#![feature(libc)]
-#![feature(ref_slice)]
#![feature(rustc_private)]
#![feature(set_stdio)]
#![feature(staged_api)]
#![feature(str_escape)]
#![feature(unicode)]
#![feature(vec_push_all)]
-#![feature(vec_resize)]
extern crate fmt_macros;
extern crate serialize;
pub mod log_syntax;
pub mod mtwt;
pub mod quote;
- pub mod pushpop_safe;
pub mod source_util;
pub mod trace_macros;
use std::fmt;
use std::iter::{IntoIterator, FromIterator};
use std::ops::Deref;
+use std::slice;
use std::vec;
use serialize::{Encodable, Decodable, Encoder, Decoder};
}
}
+impl<'a, T> IntoIterator for &'a OwnedSlice<T> {
+ type Item = &'a T;
+ type IntoIter = slice::Iter<'a, T>;
+ fn into_iter(self) -> Self::IntoIter {
+ self.data.into_iter()
+ }
+}
+
impl<T: Encodable> Encodable for OwnedSlice<T> {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
Encodable::encode(&**self, s)
token::DocComment(s) => {
let attr = ::attr::mk_sugared_doc_attr(
attr::mk_attr_id(),
- self.id_to_interned_str(s.ident()),
+ self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)),
self.span.lo,
self.span.hi
);
- if attr.node.style != ast::AttrOuter {
+ if attr.node.style != ast::AttrStyle::Outer {
panic!(self.fatal("expected outer comment"));
}
attrs.push(attr);
self.fileline_help(span,
"place inner attribute at the top of the module or block");
}
- ast::AttrInner
+ ast::AttrStyle::Inner
} else {
- ast::AttrOuter
+ ast::AttrStyle::Outer
};
panictry!(self.expect(&token::OpenDelim(token::Bracket)));
panictry!(self.bump());
self.span_warn(span, "this inner attribute syntax is deprecated. \
The new syntax is `#![foo]`, with a bang and no semicolon");
- style = ast::AttrInner;
+ style = ast::AttrStyle::Inner;
}
return Spanned {
}
let attr = self.parse_attribute(true);
- assert!(attr.node.style == ast::AttrInner);
+ assert!(attr.node.style == ast::AttrStyle::Inner);
attrs.push(attr);
}
token::DocComment(s) => {
// we need to get the position of this token before we bump.
let Span { lo, hi, .. } = self.span;
- let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(),
- self.id_to_interned_str(s.ident()),
- lo, hi);
- if attr.node.style == ast::AttrInner {
+ let str = self.id_to_interned_str(ast::Ident::with_empty_ctxt(s));
+ let attr = attr::mk_sugared_doc_attr(attr::mk_attr_id(), str, lo, hi);
+ if attr.node.style == ast::AttrStyle::Inner {
attrs.push(attr);
panictry!(self.bump());
} else {
pub fn doc_comment_style(comment: &str) -> ast::AttrStyle {
assert!(is_doc_comment(comment));
if comment.starts_with("//!") || comment.starts_with("/*!") {
- ast::AttrInner
+ ast::AttrStyle::Inner
} else {
- ast::AttrOuter
+ ast::AttrStyle::Outer
}
}
}
pub fn is_block_doc_comment(s: &str) -> bool {
- let res = (s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*')
- || s.starts_with("/*!");
+ let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*')
+ || s.starts_with("/*!"))
+ && s.len() >= 5; // Prevent `/**/` from being parsed as a doc comment
debug!("is {:?} a doc comment? {}", s, res);
res
}
Some(&ast::TtToken(_, token::Ident(name_zip, token::Plain))),
Some(&ast::TtDelimited(_, ref macro_delimed)),
)
- if name_macro_rules.name == "macro_rules"
- && name_zip.name == "zip" => {
+ if name_macro_rules.name.as_str() == "macro_rules"
+ && name_zip.name.as_str() == "zip" => {
let tts = ¯o_delimed.tts[..];
match (tts.len(), tts.get(0), tts.get(1), tts.get(2)) {
(
Some(&ast::TtToken(_, token::Ident(ident, token::Plain))),
)
if first_delimed.delim == token::Paren
- && ident.name == "a" => {},
+ && ident.name.as_str() == "a" => {},
_ => panic!("value 3: {:?}", **first_delimed),
}
let tts = &second_delimed.tts[..];
Some(&ast::TtToken(_, token::Ident(ident, token::Plain))),
)
if second_delimed.delim == token::Paren
- && ident.name == "a" => {},
+ && ident.name.as_str() == "a" => {},
_ => panic!("value 4: {:?}", **second_delimed),
}
},
"foo!( fn main() { body } )".to_string(), vec![], &sess);
let tts = match expr.node {
- ast::ExprMac(ref mac) => {
- let ast::MacInvocTT(_, ref tts, _) = mac.node;
- tts.clone()
- }
+ ast::ExprMac(ref mac) => mac.node.tts.clone(),
_ => panic!("not a macro"),
};
use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
-use ast::{ExprBreak, ExprCall, ExprCast};
+use ast::{ExprBreak, ExprCall, ExprCast, ExprInPlace};
use ast::{ExprField, ExprTupField, ExprClosure, ExprIf, ExprIfLet, ExprIndex};
use ast::{ExprLit, ExprLoop, ExprMac, ExprRange};
use ast::{ExprMethodCall, ExprParen, ExprPath};
use ast::{LitBool, LitChar, LitByte, LitByteStr};
use ast::{LitStr, LitInt, Local};
use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
-use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
+use ast::{MutImmutable, MutMutable, Mac_};
use ast::{MutTy, BiMul, Mutability};
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
use ast::PatWildSingle;
use ast::{PolyTraitRef, QSelf};
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
-use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
-use ast::{StructVariantKind, BiSub, StrStyle};
+use ast::{StmtExpr, StmtSemi, StmtMac, VariantData, StructField};
+use ast::{BiSub, StrStyle};
use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
use ast::{TtDelimited, TtSequence, TtToken};
-use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
+use ast::{Ty, Ty_, TypeBinding};
use ast::{TyMac};
use ast::{TyFixedLengthVec, TyBareFn, TyTypeof, TyInfer};
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr};
-use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
+use ast::{TyRptr, TyTup, TyU32, TyVec};
use ast::{TypeImplItem, TypeTraitItem};
use ast::{UnnamedField, UnsafeBlock};
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
this_token_str)))
}
} else {
- self.expect_one_of(slice::ref_slice(t), &[])
+ self.expect_one_of(unsafe { slice::from_raw_parts(t, 1) }, &[])
}
}
pub fn parse_ret_ty(&mut self) -> PResult<FunctionRetTy> {
if try!(self.eat(&token::RArrow) ){
if try!(self.eat(&token::Not) ){
- Ok(NoReturn(self.span))
+ Ok(NoReturn(self.last_span))
} else {
Ok(Return(try!(self.parse_ty_nopanic())))
}
seq_sep_none(),
|p| p.parse_token_tree()));
let hi = self.span.hi;
- TyMac(spanned(lo, hi, MacInvocTT(path, tts, EMPTY_CTXT)))
+ TyMac(spanned(lo, hi, Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT }))
} else {
// NAMED TYPE
TyPath(None, path)
let lo = self.span.lo;
let literal = P(try!(self.parse_lit()));
- let hi = self.span.hi;
+ let hi = self.last_span.hi;
let expr = self.mk_expr(lo, hi, ExprLit(literal));
if minus_present {
- let minus_hi = self.span.hi;
+ let minus_hi = self.last_span.hi;
let unary = self.mk_unary(UnNeg, expr);
Ok(self.mk_expr(minus_lo, minus_hi, unary))
} else {
}
}
- // QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
- // Assumes that the leading `<` has been parsed already.
+ /// Parses qualified path.
+ ///
+ /// Assumes that the leading `<` has been parsed already.
+ ///
+ /// Qualifed paths are a part of the universal function call
+ /// syntax (UFCS).
+ ///
+ /// `qualified_path = <type [as trait_ref]>::path`
+ ///
+ /// See `parse_path` for `mode` meaning.
+ ///
+ /// # Examples:
+ ///
+ /// `<T as U>::a`
+ /// `<T as U>::F::a::<S>`
pub fn parse_qualified_path(&mut self, mode: PathParsingMode)
-> PResult<(QSelf, ast::Path)> {
let span = self.last_span;
return Ok(self.mk_mac_expr(lo,
hi,
- MacInvocTT(pth,
- tts,
- EMPTY_CTXT)));
+ Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT }));
}
if self.check(&token::OpenDelim(token::Brace)) {
// This is a struct literal, unless we're prohibited
&[token::CloseDelim(token::Brace)]));
}
- if fields.is_empty() && base.is_none() {
- let last_span = self.last_span;
- self.span_err(last_span,
- "structure literal must either \
- have at least one field or use \
- structure update syntax");
- }
-
hi = self.span.hi;
try!(self.expect(&token::CloseDelim(token::Brace)));
ex = ExprStruct(pth, fields, base);
hi = e.span.hi;
ex = ExprAddrOf(m, e);
}
- token::Ident(_, _) => {
- if !self.check_keyword(keywords::Box) && !self.check_keyword(keywords::In) {
- return self.parse_dot_or_call_expr();
- }
-
- let lo = self.span.lo;
- let keyword_hi = self.span.hi;
-
- let is_in = self.token.is_keyword(keywords::In);
- try!(self.bump());
-
- if is_in {
+ token::Ident(..) if self.token.is_keyword(keywords::In) => {
+ try!(self.bump());
let place = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL));
let blk = try!(self.parse_block());
hi = blk.span.hi;
let blk_expr = self.mk_expr(blk.span.lo, blk.span.hi, ExprBlock(blk));
- ex = ExprBox(Some(place), blk_expr);
- return Ok(self.mk_expr(lo, hi, ex));
- }
-
- // FIXME (#22181) Remove `box (PLACE) EXPR` support
- // entirely after next release (enabling `(box (EXPR))`),
- // since it will be replaced by `in PLACE { EXPR }`, ...
- //
- // ... but for now: check for a place: `box(PLACE) EXPR`.
-
- if try!(self.eat(&token::OpenDelim(token::Paren))) {
- let box_span = mk_sp(lo, self.last_span.hi);
- self.span_warn(box_span,
- "deprecated syntax; use the `in` keyword now \
- (e.g. change `box (<expr>) <expr>` to \
- `in <expr> { <expr> }`)");
-
- // Continue supporting `box () EXPR` (temporarily)
- if !try!(self.eat(&token::CloseDelim(token::Paren))) {
- let place = try!(self.parse_expr_nopanic());
- try!(self.expect(&token::CloseDelim(token::Paren)));
- // Give a suggestion to use `box()` when a parenthesised expression is used
- if !self.token.can_begin_expr() {
- let span = self.span;
- let this_token_to_string = self.this_token_to_string();
- self.span_err(span,
- &format!("expected expression, found `{}`",
- this_token_to_string));
-
- // Spanning just keyword avoids constructing
- // printout of arg expression (which starts
- // with parenthesis, as established above).
-
- let box_span = mk_sp(lo, keyword_hi);
- self.span_suggestion(box_span,
- "try using `box ()` instead:",
- format!("box ()"));
- self.abort_if_errors();
- }
- let subexpression = try!(self.parse_prefix_expr());
- hi = subexpression.span.hi;
- ex = ExprBox(Some(place), subexpression);
- return Ok(self.mk_expr(lo, hi, ex));
- }
- }
-
- // Otherwise, we use the unique pointer default.
- let subexpression = try!(self.parse_prefix_expr());
- hi = subexpression.span.hi;
-
- // FIXME (pnkfelix): After working out kinks with box
- // desugaring, should be `ExprBox(None, subexpression)`
- // instead.
- ex = self.mk_unary(UnUniq, subexpression);
+ ex = ExprInPlace(place, blk_expr);
+ }
+ token::Ident(..) if self.token.is_keyword(keywords::Box) => {
+ try!(self.bump());
+ let subexpression = try!(self.parse_prefix_expr());
+ hi = subexpression.span.hi;
+ ex = ExprBox(subexpression);
}
_ => return self.parse_dot_or_call_expr()
}
}
let hi = self.span.hi;
try!(self.bump());
- return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms, MatchSource::Normal)));
+ return Ok(self.mk_expr(lo, hi, ExprMatch(discriminant, arms)));
}
pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> {
// Parse &pat / &mut pat
try!(self.expect_and());
let mutbl = try!(self.parse_mutability());
+ if let token::Lifetime(ident) = self.token {
+ return Err(self.fatal(&format!("unexpected lifetime `{}` in pattern", ident)));
+ }
+
let subpat = try!(self.parse_pat_nopanic());
pat = PatRegion(subpat, mutbl);
}
let delim = try!(self.expect_open_delim());
let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim),
seq_sep_none(), |p| p.parse_token_tree()));
- let mac = MacInvocTT(path, tts, EMPTY_CTXT);
+ let mac = Mac_ { path: path, tts: tts, ctxt: EMPTY_CTXT };
pat = PatMac(codemap::Spanned {node: mac, span: self.span});
} else {
// Parse ident @ pat
}
token::OpenDelim(token::Brace) => {
if qself.is_some() {
- let span = self.span;
- self.span_err(span,
- "unexpected `{` after qualified path");
- self.abort_if_errors();
+ return Err(self.fatal("unexpected `{` after qualified path"));
}
- // Parse struct pattern
+ // Parse struct pattern
try!(self.bump());
let (fields, etc) = try!(self.parse_pat_fields());
try!(self.bump());
}
token::OpenDelim(token::Paren) => {
if qself.is_some() {
- let span = self.span;
- self.span_err(span,
- "unexpected `(` after qualified path");
- self.abort_if_errors();
+ return Err(self.fatal("unexpected `(` after qualified path"));
}
// Parse tuple struct or enum pattern
if self.look_ahead(1, |t| *t == token::DotDot) {
pat = PatEnum(path, Some(args));
}
}
- _ if qself.is_some() => {
- // Parse qualified path
- pat = PatQPath(qself.unwrap(), path);
- }
_ => {
- // Parse nullary enum
- pat = PatEnum(path, Some(vec![]));
+ pat = match qself {
+ // Parse qualified path
+ Some(qself) => PatQPath(qself, path),
+ // Parse nullary enum
+ None => PatEnum(path, Some(vec![]))
+ };
}
}
}
spanned(lo, hi,
StmtMac(P(spanned(lo,
hi,
- MacInvocTT(pth, tts, EMPTY_CTXT))),
+ Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })),
style))
} else {
// if it has a special ident, it's definitely an item
P(spanned(lo, hi, DeclItem(
self.mk_item(
lo, hi, id /*id is good here*/,
- ItemMac(spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT))),
+ ItemMac(spanned(lo, hi,
+ Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT })),
Inherited, Vec::new(/*no attrs*/))))),
ast::DUMMY_NODE_ID))
}
/// true if we are looking at `const ID`, false for things like `const fn` etc
pub fn is_const_item(&mut self) -> bool {
self.token.is_keyword(keywords::Const) &&
- !self.look_ahead(1, |t| t.is_keyword(keywords::Fn))
+ !self.look_ahead(1, |t| t.is_keyword(keywords::Fn)) &&
+ !self.look_ahead(1, |t| t.is_keyword(keywords::Unsafe))
}
/// parses all the "front matter" for a `fn` declaration, up to
///
/// - `const fn`
/// - `unsafe fn`
+ /// - `const unsafe fn`
/// - `extern fn`
/// - etc
pub fn parse_fn_front_matter(&mut self) -> PResult<(ast::Constness, ast::Unsafety, abi::Abi)> {
let is_const_fn = try!(self.eat_keyword(keywords::Const));
+ let unsafety = try!(self.parse_unsafety());
let (constness, unsafety, abi) = if is_const_fn {
- (Constness::Const, Unsafety::Normal, abi::Rust)
+ (Constness::Const, unsafety, abi::Rust)
} else {
- let unsafety = try!(self.parse_unsafety());
let abi = if try!(self.eat_keyword(keywords::Extern)) {
try!(self.parse_opt_abi()).unwrap_or(abi::C)
} else {
let tts = try!(self.parse_seq_to_end(&token::CloseDelim(delim),
seq_sep_none(),
|p| p.parse_token_tree()));
- let m_ = ast::MacInvocTT(pth, tts, EMPTY_CTXT);
+ let m_ = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
let m: ast::Mac = codemap::Spanned { node: m_,
span: mk_sp(self.span.lo,
self.span.hi) };
// Otherwise if we look ahead and see a paren we parse a tuple-style
// struct.
- let (fields, ctor_id) = if self.token.is_keyword(keywords::Where) {
+ let vdata = if self.token.is_keyword(keywords::Where) {
generics.where_clause = try!(self.parse_where_clause());
if try!(self.eat(&token::Semi)) {
// If we see a: `struct Foo<T> where T: Copy;` style decl.
- (Vec::new(), Some(ast::DUMMY_NODE_ID))
+ VariantData::Unit(ast::DUMMY_NODE_ID)
} else {
// If we see: `struct Foo<T> where T: Copy { ... }`
- (try!(self.parse_record_struct_body(&class_name)), None)
+ VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
}
// No `where` so: `struct Foo<T>;`
} else if try!(self.eat(&token::Semi) ){
- (Vec::new(), Some(ast::DUMMY_NODE_ID))
+ VariantData::Unit(ast::DUMMY_NODE_ID)
// Record-style struct definition
} else if self.token == token::OpenDelim(token::Brace) {
- let fields = try!(self.parse_record_struct_body(&class_name));
- (fields, None)
+ VariantData::Struct(try!(self.parse_record_struct_body()), ast::DUMMY_NODE_ID)
// Tuple-style struct definition with optional where-clause.
} else if self.token == token::OpenDelim(token::Paren) {
- let fields = try!(self.parse_tuple_struct_body(&class_name, &mut generics));
- (fields, Some(ast::DUMMY_NODE_ID))
+ VariantData::Tuple(try!(self.parse_tuple_struct_body(&mut generics)),
+ ast::DUMMY_NODE_ID)
} else {
let token_str = self.this_token_to_string();
return Err(self.fatal(&format!("expected `where`, `{{`, `(`, or `;` after struct \
name, found `{}`", token_str)))
};
- Ok((class_name,
- ItemStruct(P(ast::StructDef {
- fields: fields,
- ctor_id: ctor_id,
- }), generics),
- None))
+ Ok((class_name, ItemStruct(vdata, generics), None))
}
- pub fn parse_record_struct_body(&mut self,
- class_name: &ast::Ident) -> PResult<Vec<StructField>> {
+ pub fn parse_record_struct_body(&mut self) -> PResult<Vec<StructField>> {
let mut fields = Vec::new();
if try!(self.eat(&token::OpenDelim(token::Brace)) ){
while self.token != token::CloseDelim(token::Brace) {
fields.push(try!(self.parse_struct_decl_field(true)));
}
- if fields.is_empty() {
- return Err(self.fatal(&format!("unit-like struct definition should be \
- written as `struct {};`",
- class_name)));
- }
-
try!(self.bump());
} else {
let token_str = self.this_token_to_string();
}
pub fn parse_tuple_struct_body(&mut self,
- class_name: &ast::Ident,
generics: &mut ast::Generics)
-> PResult<Vec<StructField>> {
// This is the case where we find `struct Foo<T>(T) where T: Copy;`
Ok(spanned(lo, p.span.hi, struct_field_))
}));
- if fields.is_empty() {
- return Err(self.fatal(&format!("unit-like struct definition should be \
- written as `struct {};`",
- class_name)));
- }
-
generics.where_clause = try!(self.parse_where_clause());
try!(self.expect(&token::Semi));
Ok(fields)
let hi = if self.span == codemap::DUMMY_SP {
inner_lo
} else {
- self.span.lo
+ self.last_span.hi
};
Ok(ast::Mod {
}
/// Parse a function declaration from a foreign module
- fn parse_item_foreign_fn(&mut self, vis: ast::Visibility,
+ fn parse_item_foreign_fn(&mut self, vis: ast::Visibility, lo: BytePos,
attrs: Vec<Attribute>) -> PResult<P<ForeignItem>> {
- let lo = self.span.lo;
try!(self.expect_keyword(keywords::Fn));
let (ident, mut generics) = try!(self.parse_fn_header());
}
/// Parse a static item from a foreign module
- fn parse_item_foreign_static(&mut self, vis: ast::Visibility,
+ fn parse_item_foreign_static(&mut self, vis: ast::Visibility, lo: BytePos,
attrs: Vec<Attribute>) -> PResult<P<ForeignItem>> {
- let lo = self.span.lo;
-
try!(self.expect_keyword(keywords::Static));
let mutbl = try!(self.eat_keyword(keywords::Mut));
/// Parse a structure-like enum variant definition
/// this should probably be renamed or refactored...
- fn parse_struct_def(&mut self) -> PResult<P<StructDef>> {
+ fn parse_struct_def(&mut self) -> PResult<VariantData> {
let mut fields: Vec<StructField> = Vec::new();
while self.token != token::CloseDelim(token::Brace) {
fields.push(try!(self.parse_struct_decl_field(false)));
}
try!(self.bump());
- Ok(P(StructDef {
- fields: fields,
- ctor_id: None,
- }))
+ Ok(VariantData::Struct(fields, ast::DUMMY_NODE_ID))
}
/// Parse the part of an "enum" decl following the '{'
let variant_attrs = self.parse_outer_attributes();
let vlo = self.span.lo;
- let vis = try!(self.parse_visibility());
-
- let ident;
- let kind;
- let mut args = Vec::new();
+ let struct_def;
let mut disr_expr = None;
- ident = try!(self.parse_ident());
+ let ident = try!(self.parse_ident());
if try!(self.eat(&token::OpenDelim(token::Brace)) ){
// Parse a struct variant.
all_nullary = false;
- let start_span = self.span;
- let struct_def = try!(self.parse_struct_def());
- if struct_def.fields.is_empty() {
- self.span_err(start_span,
- &format!("unit-like struct variant should be written \
- without braces, as `{},`",
- ident));
- }
- kind = StructVariantKind(struct_def);
+ struct_def = try!(self.parse_struct_def());
} else if self.check(&token::OpenDelim(token::Paren)) {
all_nullary = false;
let arg_tys = try!(self.parse_enum_variant_seq(
seq_sep_trailing_allowed(token::Comma),
|p| p.parse_ty_sum()
));
+ let mut fields = Vec::new();
for ty in arg_tys {
- args.push(ast::VariantArg {
+ fields.push(Spanned { span: ty.span, node: ast::StructField_ {
ty: ty,
+ kind: ast::UnnamedField(ast::Inherited),
+ attrs: Vec::new(),
id: ast::DUMMY_NODE_ID,
- });
+ }});
}
- kind = TupleVariantKind(args);
+ struct_def = ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID);
} else if try!(self.eat(&token::Eq) ){
disr_expr = Some(try!(self.parse_expr_nopanic()));
any_disr = disr_expr.as_ref().map(|expr| expr.span);
- kind = TupleVariantKind(args);
+ struct_def = ast::VariantData::Unit(ast::DUMMY_NODE_ID);
} else {
- kind = TupleVariantKind(Vec::new());
+ struct_def = ast::VariantData::Unit(ast::DUMMY_NODE_ID);
}
let vr = ast::Variant_ {
name: ident,
attrs: variant_attrs,
- kind: kind,
- id: ast::DUMMY_NODE_ID,
+ data: struct_def,
disr_expr: disr_expr,
- vis: vis,
};
variants.push(P(spanned(vlo, self.last_span.hi, vr)));
return Ok(Some(item));
}
if try!(self.eat_keyword(keywords::Const) ){
- if self.check_keyword(keywords::Fn) {
+ if self.check_keyword(keywords::Fn)
+ || (self.check_keyword(keywords::Unsafe)
+ && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) {
// CONST FUNCTION ITEM
+ let unsafety = if try!(self.eat_keyword(keywords::Unsafe) ){
+ Unsafety::Unsafe
+ } else {
+ Unsafety::Normal
+ };
try!(self.bump());
let (ident, item_, extra_attrs) =
- try!(self.parse_item_fn(Unsafety::Normal, Constness::Const, abi::Rust));
+ try!(self.parse_item_fn(unsafety, Constness::Const, abi::Rust));
let last_span = self.last_span;
let item = self.mk_item(lo,
last_span.hi,
if self.check_keyword(keywords::Static) {
// FOREIGN STATIC ITEM
- return Ok(Some(try!(self.parse_item_foreign_static(visibility, attrs))));
+ return Ok(Some(try!(self.parse_item_foreign_static(visibility, lo, attrs))));
}
if self.check_keyword(keywords::Fn) || self.check_keyword(keywords::Unsafe) {
// FOREIGN FUNCTION ITEM
- return Ok(Some(try!(self.parse_item_foreign_fn(visibility, attrs))));
+ return Ok(Some(try!(self.parse_item_foreign_fn(visibility, lo, attrs))));
}
// FIXME #5668: this will occur for a macro invocation:
seq_sep_none(),
|p| p.parse_token_tree()));
// single-variant-enum... :
- let m = ast::MacInvocTT(pth, tts, EMPTY_CTXT);
+ let m = Mac_ { path: pth, tts: tts, ctxt: EMPTY_CTXT };
let m: ast::Mac = codemap::Spanned { node: m,
span: mk_sp(self.span.lo,
self.span.hi) };
Option<ast::Name>)>> {
let ret = match self.token {
token::Literal(token::Str_(s), suf) => {
- (self.id_to_interned_str(s.ident()), ast::CookedStr, suf)
+ (self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)), ast::CookedStr, suf)
}
token::Literal(token::StrRaw(s, n), suf) => {
- (self.id_to_interned_str(s.ident()), ast::RawStr(n), suf)
+ (self.id_to_interned_str(ast::Ident::with_empty_ctxt(s)), ast::RawStr(n), suf)
}
_ => return Ok(None)
};
#[allow(non_upper_case_globals)]
pub const $si_static: ast::Ident = ast::Ident {
name: ast::Name($si_name),
- ctxt: 0,
+ ctxt: ast::EMPTY_CTXT,
};
)*
}
use ast;
$(
#[allow(non_upper_case_globals)]
- pub const $si_static: ast::Name = ast::Name($si_name);
+ pub const $si_static: ast::Name = ast::Name($si_name);
)*
}
/// Maps a string to an identifier with an empty syntax context.
#[inline]
pub fn str_to_ident(s: &str) -> ast::Ident {
- ast::Ident::new(intern(s))
+ ast::Ident::with_empty_ctxt(intern(s))
}
/// Maps a string to a gensym'ed identifier.
#[inline]
pub fn gensym_ident(s: &str) -> ast::Ident {
- ast::Ident::new(gensym(s))
+ ast::Ident::with_empty_ctxt(gensym(s))
}
// create a fresh name that maps to the same string as the old one.
// note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src)));
// that is, that the new name and the old one are connected to ptr_eq strings.
-pub fn fresh_name(src: &ast::Ident) -> ast::Name {
+pub fn fresh_name(src: ast::Ident) -> ast::Name {
let interner = get_ident_interner();
interner.gensym_copy(src.name)
// following: debug version. Could work in final except that it's incompatible with
// create a fresh mark.
pub fn fresh_mark() -> ast::Mrk {
- gensym("mark").usize() as u32
+ gensym("mark").0
}
#[cfg(test)]
use ext::mtwt;
fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
- ast::Ident { name: id.name, ctxt:mtwt::apply_mark(m, id.ctxt) }
+ ast::Ident::new(id.name, mtwt::apply_mark(m, id.ctxt))
}
#[test] fn mtwt_token_eq_test() {
#[derive(Copy, Clone)]
pub struct CurrentCommentAndLiteral {
- cur_cmnt: usize,
- cur_lit: usize,
+ pub cur_cmnt: usize,
+ pub cur_lit: usize,
}
pub struct State<'a> {
token::NtBlock(ref e) => block_to_string(&**e),
token::NtStmt(ref e) => stmt_to_string(&**e),
token::NtPat(ref e) => pat_to_string(&**e),
- token::NtIdent(ref e, _) => ident_to_string(&**e),
+ token::NtIdent(ref e, _) => ident_to_string(**e),
token::NtTT(ref e) => tt_to_string(&**e),
token::NtArm(ref e) => arm_to_string(&*e),
token::NtImplItem(ref e) => impl_item_to_string(&**e),
to_string(|s| s.print_path(p, false, 0))
}
-pub fn ident_to_string(id: &ast::Ident) -> String {
- to_string(|s| s.print_ident(*id))
+pub fn ident_to_string(id: ast::Ident) -> String {
+ to_string(|s| s.print_ident(id))
}
pub fn fun_to_string(decl: &ast::FnDecl,
}
}
-impl<'a> State<'a> {
- pub fn ibox(&mut self, u: usize) -> io::Result<()> {
- self.boxes.push(pp::Breaks::Inconsistent);
- pp::ibox(&mut self.s, u)
+pub trait PrintState<'a> {
+ fn writer(&mut self) -> &mut pp::Printer<'a>;
+ fn boxes(&mut self) -> &mut Vec<pp::Breaks>;
+ fn comments(&mut self) -> &mut Option<Vec<comments::Comment>>;
+ fn cur_cmnt_and_lit(&mut self) -> &mut CurrentCommentAndLiteral;
+ fn literals(&self) -> &Option<Vec<comments::Literal>>;
+
+ fn word_space(&mut self, w: &str) -> io::Result<()> {
+ try!(word(self.writer(), w));
+ space(self.writer())
}
- pub fn end(&mut self) -> io::Result<()> {
- self.boxes.pop().unwrap();
- pp::end(&mut self.s)
+ fn popen(&mut self) -> io::Result<()> { word(self.writer(), "(") }
+
+ fn pclose(&mut self) -> io::Result<()> { word(self.writer(), ")") }
+
+ fn is_begin(&mut self) -> bool {
+ match self.writer().last_token() {
+ pp::Token::Begin(_) => true,
+ _ => false,
+ }
}
- pub fn cbox(&mut self, u: usize) -> io::Result<()> {
- self.boxes.push(pp::Breaks::Consistent);
- pp::cbox(&mut self.s, u)
+ fn is_end(&mut self) -> bool {
+ match self.writer().last_token() {
+ pp::Token::End => true,
+ _ => false,
+ }
+ }
+
+ // is this the beginning of a line?
+ fn is_bol(&mut self) -> bool {
+ self.writer().last_token().is_eof() || self.writer().last_token().is_hardbreak_tok()
+ }
+
+ fn hardbreak_if_not_bol(&mut self) -> io::Result<()> {
+ if !self.is_bol() {
+ try!(hardbreak(self.writer()))
+ }
+ Ok(())
}
// "raw box"
- pub fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> {
- self.boxes.push(b);
- pp::rbox(&mut self.s, u, b)
+ fn rbox(&mut self, u: usize, b: pp::Breaks) -> io::Result<()> {
+ self.boxes().push(b);
+ pp::rbox(self.writer(), u, b)
}
- pub fn nbsp(&mut self) -> io::Result<()> { word(&mut self.s, " ") }
+ fn ibox(&mut self, u: usize) -> io::Result<()> {
+ self.boxes().push(pp::Breaks::Inconsistent);
+ pp::ibox(self.writer(), u)
+ }
- pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
- try!(word(&mut self.s, w));
- self.nbsp()
+ fn end(&mut self) -> io::Result<()> {
+ self.boxes().pop().unwrap();
+ pp::end(self.writer())
}
- pub fn word_space(&mut self, w: &str) -> io::Result<()> {
- try!(word(&mut self.s, w));
- space(&mut self.s)
+ fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()>
+ where F: FnMut(&mut Self, &T) -> io::Result<()>,
+ {
+ try!(self.rbox(0, b));
+ let mut first = true;
+ for elt in elts {
+ if first { first = false; } else { try!(self.word_space(",")); }
+ try!(op(self, elt));
+ }
+ self.end()
+ }
+
+ fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
+ let mut cur_lit = self.cur_cmnt_and_lit().cur_lit;
+
+ let mut result = None;
+
+ if let &Some(ref lits) = self.literals()
+ {
+ while cur_lit < lits.len() {
+ let ltrl = (*lits)[cur_lit].clone();
+ if ltrl.pos > pos { break; }
+ cur_lit += 1;
+ if ltrl.pos == pos {
+ result = Some(ltrl);
+ break;
+ }
+ }
+ }
+
+ self.cur_cmnt_and_lit().cur_lit = cur_lit;
+ result
+ }
+
+ fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
+ loop {
+ match self.next_comment() {
+ Some(ref cmnt) => {
+ if (*cmnt).pos < pos {
+ try!(self.print_comment(cmnt));
+ self.cur_cmnt_and_lit().cur_cmnt += 1;
+ } else { break; }
+ }
+ _ => break
+ }
+ }
+ Ok(())
+ }
+
+ fn print_comment(&mut self,
+ cmnt: &comments::Comment) -> io::Result<()> {
+ match cmnt.style {
+ comments::Mixed => {
+ assert_eq!(cmnt.lines.len(), 1);
+ try!(zerobreak(self.writer()));
+ try!(word(self.writer(), &cmnt.lines[0]));
+ zerobreak(self.writer())
+ }
+ comments::Isolated => {
+ try!(self.hardbreak_if_not_bol());
+ for line in &cmnt.lines {
+ // Don't print empty lines because they will end up as trailing
+ // whitespace
+ if !line.is_empty() {
+ try!(word(self.writer(), &line[..]));
+ }
+ try!(hardbreak(self.writer()));
+ }
+ Ok(())
+ }
+ comments::Trailing => {
+ try!(word(self.writer(), " "));
+ if cmnt.lines.len() == 1 {
+ try!(word(self.writer(), &cmnt.lines[0]));
+ hardbreak(self.writer())
+ } else {
+ try!(self.ibox(0));
+ for line in &cmnt.lines {
+ if !line.is_empty() {
+ try!(word(self.writer(), &line[..]));
+ }
+ try!(hardbreak(self.writer()));
+ }
+ self.end()
+ }
+ }
+ comments::BlankLine => {
+ // We need to do at least one, possibly two hardbreaks.
+ let is_semi = match self.writer().last_token() {
+ pp::Token::String(s, _) => ";" == s,
+ _ => false
+ };
+ if is_semi || self.is_begin() || self.is_end() {
+ try!(hardbreak(self.writer()));
+ }
+ hardbreak(self.writer())
+ }
+ }
+ }
+
+ fn next_comment(&mut self) -> Option<comments::Comment> {
+ let cur_cmnt = self.cur_cmnt_and_lit().cur_cmnt;
+ match *self.comments() {
+ Some(ref cmnts) => {
+ if cur_cmnt < cmnts.len() {
+ Some(cmnts[cur_cmnt].clone())
+ } else {
+ None
+ }
+ }
+ _ => None
+ }
+ }
+
+ fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
+ try!(self.maybe_print_comment(lit.span.lo));
+ match self.next_lit(lit.span.lo) {
+ Some(ref ltrl) => {
+ return word(self.writer(), &(*ltrl).lit);
+ }
+ _ => ()
+ }
+ match lit.node {
+ ast::LitStr(ref st, style) => self.print_string(&st, style),
+ ast::LitByte(byte) => {
+ let mut res = String::from("b'");
+ res.extend(ascii::escape_default(byte).map(|c| c as char));
+ res.push('\'');
+ word(self.writer(), &res[..])
+ }
+ ast::LitChar(ch) => {
+ let mut res = String::from("'");
+ res.extend(ch.escape_default());
+ res.push('\'');
+ word(self.writer(), &res[..])
+ }
+ ast::LitInt(i, t) => {
+ match t {
+ ast::SignedIntLit(st, ast::Plus) => {
+ word(self.writer(),
+ &ast_util::int_ty_to_string(st, Some(i as i64)))
+ }
+ ast::SignedIntLit(st, ast::Minus) => {
+ let istr = ast_util::int_ty_to_string(st, Some(-(i as i64)));
+ word(self.writer(),
+ &format!("-{}", istr))
+ }
+ ast::UnsignedIntLit(ut) => {
+ word(self.writer(), &ast_util::uint_ty_to_string(ut, Some(i)))
+ }
+ ast::UnsuffixedIntLit(ast::Plus) => {
+ word(self.writer(), &format!("{}", i))
+ }
+ ast::UnsuffixedIntLit(ast::Minus) => {
+ word(self.writer(), &format!("-{}", i))
+ }
+ }
+ }
+ ast::LitFloat(ref f, t) => {
+ word(self.writer(),
+ &format!(
+ "{}{}",
+ &f,
+ &ast_util::float_ty_to_string(t)))
+ }
+ ast::LitFloatUnsuffixed(ref f) => word(self.writer(), &f[..]),
+ ast::LitBool(val) => {
+ if val { word(self.writer(), "true") } else { word(self.writer(), "false") }
+ }
+ ast::LitByteStr(ref v) => {
+ let mut escaped: String = String::new();
+ for &ch in v.iter() {
+ escaped.extend(ascii::escape_default(ch)
+ .map(|c| c as char));
+ }
+ word(self.writer(), &format!("b\"{}\"", escaped))
+ }
+ }
+ }
+
+ fn print_string(&mut self, st: &str,
+ style: ast::StrStyle) -> io::Result<()> {
+ let st = match style {
+ ast::CookedStr => {
+ (format!("\"{}\"", st.escape_default()))
+ }
+ ast::RawStr(n) => {
+ (format!("r{delim}\"{string}\"{delim}",
+ delim=repeat("#", n),
+ string=st))
+ }
+ };
+ word(self.writer(), &st[..])
+ }
+
+ fn print_inner_attributes(&mut self,
+ attrs: &[ast::Attribute]) -> io::Result<()> {
+ let mut count = 0;
+ for attr in attrs {
+ match attr.node.style {
+ ast::AttrStyle::Inner => {
+ try!(self.print_attribute(attr));
+ count += 1;
+ }
+ _ => {/* fallthrough */ }
+ }
+ }
+ if count > 0 {
+ try!(self.hardbreak_if_not_bol());
+ }
+ Ok(())
+ }
+
+ fn print_outer_attributes(&mut self,
+ attrs: &[ast::Attribute]) -> io::Result<()> {
+ let mut count = 0;
+ for attr in attrs {
+ match attr.node.style {
+ ast::AttrStyle::Outer => {
+ try!(self.print_attribute(attr));
+ count += 1;
+ }
+ _ => {/* fallthrough */ }
+ }
+ }
+ if count > 0 {
+ try!(self.hardbreak_if_not_bol());
+ }
+ Ok(())
}
- pub fn popen(&mut self) -> io::Result<()> { word(&mut self.s, "(") }
+ fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> {
+ try!(self.hardbreak_if_not_bol());
+ try!(self.maybe_print_comment(attr.span.lo));
+ if attr.node.is_sugared_doc {
+ word(self.writer(), &attr.value_str().unwrap())
+ } else {
+ match attr.node.style {
+ ast::AttrStyle::Inner => try!(word(self.writer(), "#![")),
+ ast::AttrStyle::Outer => try!(word(self.writer(), "#[")),
+ }
+ try!(self.print_meta_item(&*attr.meta()));
+ word(self.writer(), "]")
+ }
+ }
- pub fn pclose(&mut self) -> io::Result<()> { word(&mut self.s, ")") }
+ fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
+ try!(self.ibox(indent_unit));
+ match item.node {
+ ast::MetaWord(ref name) => {
+ try!(word(self.writer(), &name));
+ }
+ ast::MetaNameValue(ref name, ref value) => {
+ try!(self.word_space(&name[..]));
+ try!(self.word_space("="));
+ try!(self.print_literal(value));
+ }
+ ast::MetaList(ref name, ref items) => {
+ try!(word(self.writer(), &name));
+ try!(self.popen());
+ try!(self.commasep(Consistent,
+ &items[..],
+ |s, i| s.print_meta_item(&**i)));
+ try!(self.pclose());
+ }
+ }
+ self.end()
+ }
+}
+
+impl<'a> PrintState<'a> for State<'a> {
+ fn writer(&mut self) -> &mut pp::Printer<'a> {
+ &mut self.s
+ }
+
+ fn boxes(&mut self) -> &mut Vec<pp::Breaks> {
+ &mut self.boxes
+ }
+
+ fn comments(&mut self) -> &mut Option<Vec<comments::Comment>> {
+ &mut self.comments
+ }
+
+ fn cur_cmnt_and_lit(&mut self) -> &mut CurrentCommentAndLiteral {
+ &mut self.cur_cmnt_and_lit
+ }
+
+ fn literals(&self) -> &Option<Vec<comments::Literal>> {
+ &self.literals
+ }
+}
+
+impl<'a> State<'a> {
+ pub fn cbox(&mut self, u: usize) -> io::Result<()> {
+ self.boxes.push(pp::Breaks::Consistent);
+ pp::cbox(&mut self.s, u)
+ }
+
+ pub fn nbsp(&mut self) -> io::Result<()> { word(&mut self.s, " ") }
+
+ pub fn word_nbsp(&mut self, w: &str) -> io::Result<()> {
+ try!(word(&mut self.s, w));
+ self.nbsp()
+ }
pub fn head(&mut self, w: &str) -> io::Result<()> {
// outer-box is consistent
self.bclose_(span, indent_unit)
}
- pub fn is_begin(&mut self) -> bool {
- match self.s.last_token() {
- pp::Token::Begin(_) => true,
- _ => false,
- }
- }
-
- pub fn is_end(&mut self) -> bool {
- match self.s.last_token() {
- pp::Token::End => true,
- _ => false,
- }
- }
-
- // is this the beginning of a line?
- pub fn is_bol(&mut self) -> bool {
- self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok()
- }
-
pub fn in_cbox(&self) -> bool {
match self.boxes.last() {
Some(&last_box) => last_box == pp::Breaks::Consistent,
}
}
- pub fn hardbreak_if_not_bol(&mut self) -> io::Result<()> {
- if !self.is_bol() {
- try!(hardbreak(&mut self.s))
- }
- Ok(())
- }
pub fn space_if_not_bol(&mut self) -> io::Result<()> {
if !self.is_bol() { try!(space(&mut self.s)); }
Ok(())
word(&mut self.s, "*/")
}
- pub fn commasep<T, F>(&mut self, b: Breaks, elts: &[T], mut op: F) -> io::Result<()> where
- F: FnMut(&mut State, &T) -> io::Result<()>,
- {
- try!(self.rbox(0, b));
- let mut first = true;
- for elt in elts {
- if first { first = false; } else { try!(self.word_space(",")); }
- try!(op(self, elt));
- }
- self.end()
- }
pub fn commasep_cmnt<T, F, G>(&mut self,
}
ast::ItemStruct(ref struct_def, ref generics) => {
try!(self.head(&visibility_qualified(item.vis,"struct")));
- try!(self.print_struct(&**struct_def, generics, item.ident, item.span));
+ try!(self.print_struct(&struct_def, generics, item.ident, item.span, true));
}
ast::ItemDefaultImpl(unsafety, ref trait_ref) => {
}
try!(self.bclose(item.span));
}
- // I think it's reasonable to hide the context here:
- ast::ItemMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
- ..}) => {
+ ast::ItemMac(codemap::Spanned { ref node, .. }) => {
try!(self.print_visibility(item.vis));
- try!(self.print_path(pth, false, 0));
+ try!(self.print_path(&node.path, false, 0));
try!(word(&mut self.s, "! "));
try!(self.print_ident(item.ident));
try!(self.cbox(indent_unit));
try!(self.popen());
- try!(self.print_tts(&tts[..]));
+ try!(self.print_tts(&node.tts[..]));
try!(self.pclose());
try!(word(&mut self.s, ";"));
try!(self.end());
}
pub fn print_struct(&mut self,
- struct_def: &ast::StructDef,
+ struct_def: &ast::VariantData,
generics: &ast::Generics,
ident: ast::Ident,
- span: codemap::Span) -> io::Result<()> {
+ span: codemap::Span,
+ print_finalizer: bool) -> io::Result<()> {
try!(self.print_ident(ident));
try!(self.print_generics(generics));
- if ast_util::struct_def_is_tuple_like(struct_def) {
- if !struct_def.fields.is_empty() {
+ if !struct_def.is_struct() {
+ if struct_def.is_tuple() {
try!(self.popen());
try!(self.commasep(
- Inconsistent, &struct_def.fields,
+ Inconsistent, struct_def.fields(),
|s, field| {
match field.node.kind {
ast::NamedField(..) => panic!("unexpected named field"),
try!(self.pclose());
}
try!(self.print_where_clause(&generics.where_clause));
- try!(word(&mut self.s, ";"));
+ if print_finalizer {
+ try!(word(&mut self.s, ";"));
+ }
try!(self.end());
self.end() // close the outer-box
} else {
try!(self.bopen());
try!(self.hardbreak_if_not_bol());
- for field in &struct_def.fields {
+ for field in struct_def.fields() {
match field.node.kind {
ast::UnnamedField(..) => panic!("unexpected unnamed field"),
ast::NamedField(ident, visibility) => {
}
pub fn print_variant(&mut self, v: &ast::Variant) -> io::Result<()> {
- try!(self.print_visibility(v.node.vis));
- match v.node.kind {
- ast::TupleVariantKind(ref args) => {
- try!(self.print_ident(v.node.name));
- if !args.is_empty() {
- try!(self.popen());
- try!(self.commasep(Consistent,
- &args[..],
- |s, arg| s.print_type(&*arg.ty)));
- try!(self.pclose());
- }
- }
- ast::StructVariantKind(ref struct_def) => {
- try!(self.head(""));
- let generics = ast_util::empty_generics();
- try!(self.print_struct(&**struct_def, &generics, v.node.name, v.span));
- }
- }
+ try!(self.head(""));
+ let generics = ast_util::empty_generics();
+ try!(self.print_struct(&v.node.data, &generics, v.node.name, v.span, false));
match v.node.disr_expr {
Some(ref d) => {
try!(space(&mut self.s));
ast::TypeImplItem(ref ty) => {
try!(self.print_associated_type(ii.ident, None, Some(ty)));
}
- ast::MacImplItem(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
- ..}) => {
+ ast::MacImplItem(codemap::Spanned { ref node, .. }) => {
// code copied from ItemMac:
- try!(self.print_path(pth, false, 0));
+ try!(self.print_path(&node.path, false, 0));
try!(word(&mut self.s, "! "));
try!(self.cbox(indent_unit));
try!(self.popen());
- try!(self.print_tts(&tts[..]));
+ try!(self.print_tts(&node.tts[..]));
try!(self.pclose());
try!(word(&mut self.s, ";"));
try!(self.end())
self.ann.post(self, NodeSubItem(ii.id))
}
- pub fn print_outer_attributes(&mut self,
- attrs: &[ast::Attribute]) -> io::Result<()> {
- let mut count = 0;
- for attr in attrs {
- match attr.node.style {
- ast::AttrOuter => {
- try!(self.print_attribute(attr));
- count += 1;
- }
- _ => {/* fallthrough */ }
- }
- }
- if count > 0 {
- try!(self.hardbreak_if_not_bol());
- }
- Ok(())
- }
-
- pub fn print_inner_attributes(&mut self,
- attrs: &[ast::Attribute]) -> io::Result<()> {
- let mut count = 0;
- for attr in attrs {
- match attr.node.style {
- ast::AttrInner => {
- try!(self.print_attribute(attr));
- count += 1;
- }
- _ => {/* fallthrough */ }
- }
- }
- if count > 0 {
- try!(self.hardbreak_if_not_bol());
- }
- Ok(())
- }
-
- pub fn print_attribute(&mut self, attr: &ast::Attribute) -> io::Result<()> {
- try!(self.hardbreak_if_not_bol());
- try!(self.maybe_print_comment(attr.span.lo));
- if attr.node.is_sugared_doc {
- word(&mut self.s, &attr.value_str().unwrap())
- } else {
- match attr.node.style {
- ast::AttrInner => try!(word(&mut self.s, "#![")),
- ast::AttrOuter => try!(word(&mut self.s, "#[")),
- }
- try!(self.print_meta_item(&*attr.meta()));
- word(&mut self.s, "]")
- }
- }
-
-
pub fn print_stmt(&mut self, st: &ast::Stmt) -> io::Result<()> {
try!(self.maybe_print_comment(st.span.lo));
match st.node {
attrs: &[ast::Attribute],
close_box: bool) -> io::Result<()> {
match blk.rules {
- ast::UnsafeBlock(..) | ast::PushUnsafeBlock(..) => try!(self.word_space("unsafe")),
- ast::DefaultBlock | ast::PopUnsafeBlock(..) => ()
+ ast::UnsafeBlock(..) => try!(self.word_space("unsafe")),
+ ast::DefaultBlock => ()
}
try!(self.maybe_print_comment(blk.span.lo));
try!(self.ann.pre(self, NodeBlock(blk)));
pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
-> io::Result<()> {
- match m.node {
- // I think it's reasonable to hide the ctxt here:
- ast::MacInvocTT(ref pth, ref tts, _) => {
- try!(self.print_path(pth, false, 0));
- try!(word(&mut self.s, "!"));
- match delim {
- token::Paren => try!(self.popen()),
- token::Bracket => try!(word(&mut self.s, "[")),
- token::Brace => try!(self.bopen()),
- }
- try!(self.print_tts(tts));
- match delim {
- token::Paren => self.pclose(),
- token::Bracket => word(&mut self.s, "]"),
- token::Brace => self.bclose(m.span),
- }
- }
+ try!(self.print_path(&m.node.path, false, 0));
+ try!(word(&mut self.s, "!"));
+ match delim {
+ token::Paren => try!(self.popen()),
+ token::Bracket => try!(word(&mut self.s, "[")),
+ token::Brace => try!(self.bopen()),
+ }
+ try!(self.print_tts(&m.node.tts));
+ match delim {
+ token::Paren => self.pclose(),
+ token::Bracket => word(&mut self.s, "]"),
+ token::Brace => self.bclose(m.span),
}
}
Ok(())
}
- fn print_expr_box(&mut self,
- place: &Option<P<ast::Expr>>,
- expr: &ast::Expr) -> io::Result<()> {
- try!(word(&mut self.s, "box"));
- try!(word(&mut self.s, "("));
- try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
- try!(self.word_space(")"));
+ fn print_expr_in_place(&mut self,
+ place: &ast::Expr,
+ expr: &ast::Expr) -> io::Result<()> {
+ try!(self.word_space("in"));
+ try!(self.print_expr(place));
+ try!(space(&mut self.s));
self.print_expr(expr)
}
fields: &[ast::Field],
wth: &Option<P<ast::Expr>>) -> io::Result<()> {
try!(self.print_path(path, true, 0));
- if !(fields.is_empty() && wth.is_none()) {
- try!(word(&mut self.s, "{"));
- try!(self.commasep_cmnt(
- Consistent,
- &fields[..],
- |s, field| {
- try!(s.ibox(indent_unit));
- try!(s.print_ident(field.ident.node));
- try!(s.word_space(":"));
- try!(s.print_expr(&*field.expr));
- s.end()
- },
- |f| f.span));
- match *wth {
- Some(ref expr) => {
- try!(self.ibox(indent_unit));
- if !fields.is_empty() {
- try!(word(&mut self.s, ","));
- try!(space(&mut self.s));
- }
- try!(word(&mut self.s, ".."));
- try!(self.print_expr(&**expr));
- try!(self.end());
+ try!(word(&mut self.s, "{"));
+ try!(self.commasep_cmnt(
+ Consistent,
+ &fields[..],
+ |s, field| {
+ try!(s.ibox(indent_unit));
+ try!(s.print_ident(field.ident.node));
+ try!(s.word_space(":"));
+ try!(s.print_expr(&*field.expr));
+ s.end()
+ },
+ |f| f.span));
+ match *wth {
+ Some(ref expr) => {
+ try!(self.ibox(indent_unit));
+ if !fields.is_empty() {
+ try!(word(&mut self.s, ","));
+ try!(space(&mut self.s));
}
- _ => try!(word(&mut self.s, ",")),
+ try!(word(&mut self.s, ".."));
+ try!(self.print_expr(&**expr));
+ try!(self.end());
+ }
+ _ => if !fields.is_empty() {
+ try!(word(&mut self.s, ","))
}
- try!(word(&mut self.s, "}"));
}
+ try!(word(&mut self.s, "}"));
Ok(())
}
try!(self.ibox(indent_unit));
try!(self.ann.pre(self, NodeExpr(expr)));
match expr.node {
- ast::ExprBox(ref place, ref expr) => {
- try!(self.print_expr_box(place, &**expr));
+ ast::ExprBox(ref expr) => {
+ try!(self.word_space("box"));
+ try!(self.print_expr(expr));
+ }
+ ast::ExprInPlace(ref place, ref expr) => {
+ try!(self.print_expr_in_place(place, expr));
}
ast::ExprVec(ref exprs) => {
try!(self.print_expr_vec(&exprs[..]));
try!(space(&mut self.s));
try!(self.print_block(&**blk));
}
- ast::ExprMatch(ref expr, ref arms, _) => {
+ ast::ExprMatch(ref expr, ref arms) => {
try!(self.cbox(indent_unit));
try!(self.ibox(4));
try!(self.word_nbsp("match"));
if a.alignstack {
options.push("alignstack");
}
- if a.dialect == ast::AsmDialect::AsmIntel {
+ if a.dialect == ast::AsmDialect::Intel {
options.push("intel");
}
Ok(())
}
- pub fn print_meta_item(&mut self, item: &ast::MetaItem) -> io::Result<()> {
- try!(self.ibox(indent_unit));
- match item.node {
- ast::MetaWord(ref name) => {
- try!(word(&mut self.s, &name));
- }
- ast::MetaNameValue(ref name, ref value) => {
- try!(self.word_space(&name[..]));
- try!(self.word_space("="));
- try!(self.print_literal(value));
- }
- ast::MetaList(ref name, ref items) => {
- try!(word(&mut self.s, &name));
- try!(self.popen());
- try!(self.commasep(Consistent,
- &items[..],
- |s, i| s.print_meta_item(&**i)));
- try!(self.pclose());
- }
- }
- self.end()
- }
-
pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
match vp.node {
ast::ViewPathSimple(ident, ref path) => {
try!(self.print_path(path, false, 0));
- // FIXME(#6993) can't compare identifiers directly here
if path.segments.last().unwrap().identifier.name !=
ident.name {
try!(space(&mut self.s));
Ok(())
}
- pub fn print_literal(&mut self, lit: &ast::Lit) -> io::Result<()> {
- try!(self.maybe_print_comment(lit.span.lo));
- match self.next_lit(lit.span.lo) {
- Some(ref ltrl) => {
- return word(&mut self.s, &(*ltrl).lit);
- }
- _ => ()
- }
- match lit.node {
- ast::LitStr(ref st, style) => self.print_string(&st, style),
- ast::LitByte(byte) => {
- let mut res = String::from("b'");
- res.extend(ascii::escape_default(byte).map(|c| c as char));
- res.push('\'');
- word(&mut self.s, &res[..])
- }
- ast::LitChar(ch) => {
- let mut res = String::from("'");
- res.extend(ch.escape_default());
- res.push('\'');
- word(&mut self.s, &res[..])
- }
- ast::LitInt(i, t) => {
- match t {
- ast::SignedIntLit(st, ast::Plus) => {
- word(&mut self.s,
- &ast_util::int_ty_to_string(st, Some(i as i64)))
- }
- ast::SignedIntLit(st, ast::Minus) => {
- let istr = ast_util::int_ty_to_string(st, Some(-(i as i64)));
- word(&mut self.s,
- &format!("-{}", istr))
- }
- ast::UnsignedIntLit(ut) => {
- word(&mut self.s, &ast_util::uint_ty_to_string(ut, Some(i)))
- }
- ast::UnsuffixedIntLit(ast::Plus) => {
- word(&mut self.s, &format!("{}", i))
- }
- ast::UnsuffixedIntLit(ast::Minus) => {
- word(&mut self.s, &format!("-{}", i))
- }
- }
- }
- ast::LitFloat(ref f, t) => {
- word(&mut self.s,
- &format!(
- "{}{}",
- &f,
- &ast_util::float_ty_to_string(t)))
- }
- ast::LitFloatUnsuffixed(ref f) => word(&mut self.s, &f[..]),
- ast::LitBool(val) => {
- if val { word(&mut self.s, "true") } else { word(&mut self.s, "false") }
- }
- ast::LitByteStr(ref v) => {
- let mut escaped: String = String::new();
- for &ch in v.iter() {
- escaped.extend(ascii::escape_default(ch)
- .map(|c| c as char));
- }
- word(&mut self.s, &format!("b\"{}\"", escaped))
- }
- }
- }
-
- pub fn next_lit(&mut self, pos: BytePos) -> Option<comments::Literal> {
- match self.literals {
- Some(ref lits) => {
- while self.cur_cmnt_and_lit.cur_lit < lits.len() {
- let ltrl = (*lits)[self.cur_cmnt_and_lit.cur_lit].clone();
- if ltrl.pos > pos { return None; }
- self.cur_cmnt_and_lit.cur_lit += 1;
- if ltrl.pos == pos { return Some(ltrl); }
- }
- None
- }
- _ => None
- }
- }
-
- pub fn maybe_print_comment(&mut self, pos: BytePos) -> io::Result<()> {
- loop {
- match self.next_comment() {
- Some(ref cmnt) => {
- if (*cmnt).pos < pos {
- try!(self.print_comment(cmnt));
- self.cur_cmnt_and_lit.cur_cmnt += 1;
- } else { break; }
- }
- _ => break
- }
- }
- Ok(())
- }
-
- pub fn print_comment(&mut self,
- cmnt: &comments::Comment) -> io::Result<()> {
- match cmnt.style {
- comments::Mixed => {
- assert_eq!(cmnt.lines.len(), 1);
- try!(zerobreak(&mut self.s));
- try!(word(&mut self.s, &cmnt.lines[0]));
- zerobreak(&mut self.s)
- }
- comments::Isolated => {
- try!(self.hardbreak_if_not_bol());
- for line in &cmnt.lines {
- // Don't print empty lines because they will end up as trailing
- // whitespace
- if !line.is_empty() {
- try!(word(&mut self.s, &line[..]));
- }
- try!(hardbreak(&mut self.s));
- }
- Ok(())
- }
- comments::Trailing => {
- try!(word(&mut self.s, " "));
- if cmnt.lines.len() == 1 {
- try!(word(&mut self.s, &cmnt.lines[0]));
- hardbreak(&mut self.s)
- } else {
- try!(self.ibox(0));
- for line in &cmnt.lines {
- if !line.is_empty() {
- try!(word(&mut self.s, &line[..]));
- }
- try!(hardbreak(&mut self.s));
- }
- self.end()
- }
- }
- comments::BlankLine => {
- // We need to do at least one, possibly two hardbreaks.
- let is_semi = match self.s.last_token() {
- pp::Token::String(s, _) => ";" == s,
- _ => false
- };
- if is_semi || self.is_begin() || self.is_end() {
- try!(hardbreak(&mut self.s));
- }
- hardbreak(&mut self.s)
- }
- }
- }
-
- pub fn print_string(&mut self, st: &str,
- style: ast::StrStyle) -> io::Result<()> {
- let st = match style {
- ast::CookedStr => {
- (format!("\"{}\"", st.escape_default()))
- }
- ast::RawStr(n) => {
- (format!("r{delim}\"{string}\"{delim}",
- delim=repeat("#", n),
- string=st))
- }
- };
- word(&mut self.s, &st[..])
- }
-
- pub fn next_comment(&mut self) -> Option<comments::Comment> {
- match self.comments {
- Some(ref cmnts) => {
- if self.cur_cmnt_and_lit.cur_cmnt < cmnts.len() {
- Some(cmnts[self.cur_cmnt_and_lit.cur_cmnt].clone())
- } else {
- None
- }
- }
- _ => None
- }
- }
-
pub fn print_opt_abi_and_extern_if_nondefault(&mut self,
opt_abi: Option<abi::Abi>)
-> io::Result<()> {
abi: abi::Abi,
vis: ast::Visibility) -> io::Result<()> {
try!(word(&mut self.s, &visibility_qualified(vis, "")));
- try!(self.print_unsafety(unsafety));
match constness {
ast::Constness::NotConst => {}
ast::Constness::Const => try!(self.word_nbsp("const"))
}
+ try!(self.print_unsafety(unsafety));
+
if abi != abi::Rust {
try!(self.word_nbsp("extern"));
try!(self.word_nbsp(&abi.to_string()));
name: ident,
attrs: Vec::new(),
// making this up as I go.... ?
- kind: ast::TupleVariantKind(Vec::new()),
- id: 0,
+ data: ast::VariantData::Unit(ast::DUMMY_NODE_ID),
disr_expr: None,
- vis: ast::Public,
});
let varstr = variant_to_string(&var);
- assert_eq!(varstr, "pub principal_skinner");
+ assert_eq!(varstr, "principal_skinner");
}
#[test]
span: self.span,
node: ast::Attribute_ {
id: attr::mk_attr_id(),
- style: ast::AttrOuter,
+ style: ast::AttrStyle::Outer,
value: P(ast::MetaItem {
span: self.span,
node: ast::MetaWord(special_idents::prelude_import.name.as_str()),
pub fn get(&self, idx: Name) -> T {
let vect = self.vect.borrow();
- (*vect)[idx.usize()].clone()
+ (*vect)[idx.0 as usize].clone()
}
pub fn len(&self) -> usize {
let new_idx = Name(self.len() as u32);
// leave out of map to avoid colliding
let mut vect = self.vect.borrow_mut();
- let existing = (*vect)[idx.usize()].clone();
+ let existing = (*vect)[idx.0 as usize].clone();
vect.push(existing);
new_idx
}
pub fn get(&self, idx: Name) -> RcStr {
- (*self.vect.borrow())[idx.usize()].clone()
+ (*self.vect.borrow())[idx.0 as usize].clone()
}
pub fn len(&self) -> usize {
result
}
One(ref v) => {
- // FIXME: Could be replaced with `slice::ref_slice(v)` when it is stable.
unsafe { slice::from_raw_parts(v, 1) }
}
Many(ref vs) => vs
}
/// Deprecated: use `into_iter`.
- #[unstable(feature = "rustc_private")]
+ #[unstable(feature = "rustc_private", issue = "0")]
#[deprecated(since = "1.0.0", reason = "use into_iter")]
pub fn move_iter(self) -> IntoIter<T> {
self.into_iter()
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
use abi::Abi;
use ast::*;
-use ast;
use codemap::Span;
-use ptr::P;
-use owned_slice::OwnedSlice;
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum FnKind<'a> {
// Nothing to do.
}
fn visit_ident(&mut self, span: Span, ident: Ident) {
- self.visit_name(span, ident.name);
+ walk_ident(self, span, ident);
}
fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) { walk_mod(self, m) }
fn visit_foreign_item(&mut self, i: &'v ForeignItem) { walk_foreign_item(self, i) }
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
- fn visit_struct_def(&mut self, s: &'v StructDef, _: Ident, _: &'v Generics, _: NodeId) {
+ fn visit_variant_data(&mut self, s: &'v VariantData, _: Ident,
+ _: &'v Generics, _: NodeId, _: Span) {
walk_struct_def(self, s)
}
fn visit_struct_field(&mut self, s: &'v StructField) { walk_struct_field(self, s) }
fn visit_enum_def(&mut self, enum_definition: &'v EnumDef,
- generics: &'v Generics) {
- walk_enum_def(self, enum_definition, generics)
+ generics: &'v Generics, item_id: NodeId, _: Span) {
+ walk_enum_def(self, enum_definition, generics, item_id)
}
-
- fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics) { walk_variant(self, v, g) }
-
- /// Visits an optional reference to a lifetime. The `span` is the span of some surrounding
- /// reference should opt_lifetime be None.
- fn visit_opt_lifetime_ref(&mut self,
- _span: Span,
- opt_lifetime: &'v Option<Lifetime>) {
- match *opt_lifetime {
- Some(ref l) => self.visit_lifetime_ref(l),
- None => ()
- }
- }
- fn visit_lifetime_bound(&mut self, lifetime: &'v Lifetime) {
- walk_lifetime_bound(self, lifetime)
+ fn visit_variant(&mut self, v: &'v Variant, g: &'v Generics, item_id: NodeId) {
+ walk_variant(self, v, g, item_id)
}
- fn visit_lifetime_ref(&mut self, lifetime: &'v Lifetime) {
- walk_lifetime_ref(self, lifetime)
+ fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
+ walk_lifetime(self, lifetime)
}
fn visit_lifetime_def(&mut self, lifetime: &'v LifetimeDef) {
walk_lifetime_def(self, lifetime)
// definition in your trait impl:
// visit::walk_mac(self, _mac)
}
- fn visit_path(&mut self, path: &'v Path, _id: ast::NodeId) {
+ fn visit_path(&mut self, path: &'v Path, _id: NodeId) {
walk_path(self, path)
}
+ fn visit_path_list_item(&mut self, prefix: &'v Path, item: &'v PathListItem) {
+ walk_path_list_item(self, prefix, item)
+ }
fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) {
walk_path_segment(self, path_span, path_segment)
}
walk_assoc_type_binding(self, type_binding)
}
fn visit_attribute(&mut self, _attr: &'v Attribute) {}
+ fn visit_macro_def(&mut self, macro_def: &'v MacroDef) {
+ walk_macro_def(self, macro_def)
+ }
}
-pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
- visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
- for attr in &krate.attrs {
- visitor.visit_attribute(attr);
+#[macro_export]
+macro_rules! walk_list {
+ ($visitor: expr, $method: ident, $list: expr) => {
+ for elem in $list {
+ $visitor.$method(elem)
+ }
+ };
+ ($visitor: expr, $method: ident, $list: expr, $($extra_args: expr),*) => {
+ for elem in $list {
+ $visitor.$method(elem, $($extra_args,)*)
+ }
}
}
-pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
- for item in &module.items {
- visitor.visit_item(&**item)
+pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name: Option<Name>) {
+ for name in opt_name {
+ visitor.visit_name(span, name);
}
}
-pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
- visitor.visit_pat(&*local.pat);
- walk_ty_opt(visitor, &local.ty);
- walk_expr_opt(visitor, &local.init);
+pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option<Ident>) {
+ for ident in opt_ident {
+ visitor.visit_ident(span, ident);
+ }
}
-pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetime_def: &'v LifetimeDef) {
- visitor.visit_name(lifetime_def.lifetime.span, lifetime_def.lifetime.name);
- for bound in &lifetime_def.bounds {
- visitor.visit_lifetime_bound(bound);
- }
+pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) {
+ visitor.visit_name(span, ident.name);
+}
+
+pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
+ visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
+ walk_list!(visitor, visit_attribute, &krate.attrs);
+ walk_list!(visitor, visit_macro_def, &krate.exported_macros);
+}
+
+pub fn walk_macro_def<'v, V: Visitor<'v>>(visitor: &mut V, macro_def: &'v MacroDef) {
+ visitor.visit_ident(macro_def.span, macro_def.ident);
+ walk_opt_ident(visitor, macro_def.span, macro_def.imported_from);
+ walk_list!(visitor, visit_attribute, ¯o_def.attrs);
}
-pub fn walk_lifetime_bound<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetime_ref: &'v Lifetime) {
- visitor.visit_lifetime_ref(lifetime_ref)
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod) {
+ walk_list!(visitor, visit_item, &module.items);
}
-pub fn walk_lifetime_ref<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetime_ref: &'v Lifetime) {
- visitor.visit_name(lifetime_ref.span, lifetime_ref.name)
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
+ visitor.visit_pat(&local.pat);
+ walk_list!(visitor, visit_ty, &local.ty);
+ walk_list!(visitor, visit_expr, &local.init);
+}
+
+pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
+ visitor.visit_name(lifetime.span, lifetime.name);
+}
+
+pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V,
+ lifetime_def: &'v LifetimeDef) {
+ visitor.visit_lifetime(&lifetime_def.lifetime);
+ walk_list!(visitor, visit_lifetime, &lifetime_def.bounds);
}
pub fn walk_explicit_self<'v, V: Visitor<'v>>(visitor: &mut V,
explicit_self: &'v ExplicitSelf) {
match explicit_self.node {
- SelfStatic | SelfValue(_) => {},
- SelfRegion(ref lifetime, _, _) => {
- visitor.visit_opt_lifetime_ref(explicit_self.span, lifetime)
+ SelfStatic => {},
+ SelfValue(ident) => {
+ visitor.visit_ident(explicit_self.span, ident)
+ }
+ SelfRegion(ref opt_lifetime, _, ident) => {
+ visitor.visit_ident(explicit_self.span, ident);
+ walk_list!(visitor, visit_lifetime, opt_lifetime);
+ }
+ SelfExplicit(ref typ, ident) => {
+ visitor.visit_ident(explicit_self.span, ident);
+ visitor.visit_ty(typ)
}
- SelfExplicit(ref typ, _) => visitor.visit_ty(&**typ),
}
}
_modifier: &'v TraitBoundModifier)
where V: Visitor<'v>
{
- walk_lifetime_decls_helper(visitor, &trait_ref.bound_lifetimes);
+ walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
visitor.visit_trait_ref(&trait_ref.trait_ref);
}
pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) {
visitor.visit_ident(item.span, item.ident);
match item.node {
- ItemExternCrate(..) => {}
+ ItemExternCrate(opt_name) => {
+ walk_opt_name(visitor, item.span, opt_name)
+ }
ItemUse(ref vp) => {
match vp.node {
ViewPathSimple(ident, ref path) => {
visitor.visit_path(path, item.id);
}
ViewPathList(ref prefix, ref list) => {
- for id in list {
- match id.node {
- PathListIdent { name, rename, .. } => {
- visitor.visit_ident(id.span, name);
- if let Some(ident) = rename {
- visitor.visit_ident(id.span, ident);
- }
- }
- PathListMod { rename, .. } => {
- if let Some(ident) = rename {
- visitor.visit_ident(id.span, ident);
- }
- }
+ if !list.is_empty() {
+ for item in list {
+ visitor.visit_path_list_item(prefix, item)
}
+ } else {
+ visitor.visit_path(prefix, item.id);
}
-
- // Note that the `prefix` here is not a complete
- // path, so we don't use `visit_path`.
- walk_path(visitor, prefix);
}
}
}
ItemStatic(ref typ, _, ref expr) |
ItemConst(ref typ, ref expr) => {
- visitor.visit_ty(&**typ);
- visitor.visit_expr(&**expr);
+ visitor.visit_ty(typ);
+ visitor.visit_expr(expr);
}
ItemFn(ref declaration, unsafety, constness, abi, ref generics, ref body) => {
visitor.visit_fn(FnKind::ItemFn(item.ident, generics, unsafety,
constness, abi, item.vis),
- &**declaration,
- &**body,
+ declaration,
+ body,
item.span,
item.id)
}
visitor.visit_mod(module, item.span, item.id)
}
ItemForeignMod(ref foreign_module) => {
- for foreign_item in &foreign_module.items {
- visitor.visit_foreign_item(&**foreign_item)
- }
+ walk_list!(visitor, visit_foreign_item, &foreign_module.items);
}
ItemTy(ref typ, ref type_parameters) => {
- visitor.visit_ty(&**typ);
+ visitor.visit_ty(typ);
visitor.visit_generics(type_parameters)
}
ItemEnum(ref enum_definition, ref type_parameters) => {
visitor.visit_generics(type_parameters);
- visitor.visit_enum_def(enum_definition, type_parameters)
+ visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span)
}
ItemDefaultImpl(_, ref trait_ref) => {
visitor.visit_trait_ref(trait_ref)
}
ItemImpl(_, _,
ref type_parameters,
- ref trait_reference,
+ ref opt_trait_reference,
ref typ,
ref impl_items) => {
visitor.visit_generics(type_parameters);
- match *trait_reference {
- Some(ref trait_reference) => visitor.visit_trait_ref(trait_reference),
- None => ()
- }
- visitor.visit_ty(&**typ);
- for impl_item in impl_items {
- visitor.visit_impl_item(impl_item);
- }
+ walk_list!(visitor, visit_trait_ref, opt_trait_reference);
+ visitor.visit_ty(typ);
+ walk_list!(visitor, visit_impl_item, impl_items);
}
ItemStruct(ref struct_definition, ref generics) => {
visitor.visit_generics(generics);
- visitor.visit_struct_def(&**struct_definition,
- item.ident,
- generics,
- item.id)
+ visitor.visit_variant_data(struct_definition, item.ident,
+ generics, item.id, item.span);
}
ItemTrait(_, ref generics, ref bounds, ref methods) => {
visitor.visit_generics(generics);
- walk_ty_param_bounds_helper(visitor, bounds);
- for method in methods {
- visitor.visit_trait_item(method)
- }
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_trait_item, methods);
}
ItemMac(ref mac) => visitor.visit_mac(mac),
}
- for attr in &item.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_list!(visitor, visit_attribute, &item.attrs);
}
pub fn walk_enum_def<'v, V: Visitor<'v>>(visitor: &mut V,
enum_definition: &'v EnumDef,
- generics: &'v Generics) {
- for variant in &enum_definition.variants {
- visitor.visit_variant(&**variant, generics);
- }
+ generics: &'v Generics,
+ item_id: NodeId) {
+ walk_list!(visitor, visit_variant, &enum_definition.variants, generics, item_id);
}
pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V,
variant: &'v Variant,
- generics: &'v Generics) {
+ generics: &'v Generics,
+ item_id: NodeId) {
visitor.visit_ident(variant.span, variant.node.name);
-
- match variant.node.kind {
- TupleVariantKind(ref variant_arguments) => {
- for variant_argument in variant_arguments {
- visitor.visit_ty(&*variant_argument.ty)
- }
- }
- StructVariantKind(ref struct_definition) => {
- visitor.visit_struct_def(&**struct_definition,
- variant.node.name,
- generics,
- variant.node.id)
- }
- }
- match variant.node.disr_expr {
- Some(ref expr) => visitor.visit_expr(&**expr),
- None => ()
- }
- for attr in &variant.node.attrs {
- visitor.visit_attribute(attr);
- }
-}
-
-pub fn skip_ty<'v, V: Visitor<'v>>(_: &mut V, _: &'v Ty) {
- // Empty!
-}
-
-pub fn walk_ty_opt<'v, V: Visitor<'v>>(visitor: &mut V, optional_type: &'v Option<P<Ty>>) {
- match *optional_type {
- Some(ref ty) => visitor.visit_ty(&**ty),
- None => ()
- }
+ visitor.visit_variant_data(&variant.node.data, variant.node.name,
+ generics, item_id, variant.span);
+ walk_list!(visitor, visit_expr, &variant.node.disr_expr);
+ walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
match typ.node {
TyVec(ref ty) | TyParen(ref ty) => {
- visitor.visit_ty(&**ty)
+ visitor.visit_ty(ty)
}
TyPtr(ref mutable_type) => {
- visitor.visit_ty(&*mutable_type.ty)
+ visitor.visit_ty(&mutable_type.ty)
}
- TyRptr(ref lifetime, ref mutable_type) => {
- visitor.visit_opt_lifetime_ref(typ.span, lifetime);
- visitor.visit_ty(&*mutable_type.ty)
+ TyRptr(ref opt_lifetime, ref mutable_type) => {
+ walk_list!(visitor, visit_lifetime, opt_lifetime);
+ visitor.visit_ty(&mutable_type.ty)
}
TyTup(ref tuple_element_types) => {
- for tuple_element_type in tuple_element_types {
- visitor.visit_ty(&**tuple_element_type)
- }
+ walk_list!(visitor, visit_ty, tuple_element_types);
}
TyBareFn(ref function_declaration) => {
- for argument in &function_declaration.decl.inputs {
- visitor.visit_ty(&*argument.ty)
- }
- walk_fn_ret_ty(visitor, &function_declaration.decl.output);
- walk_lifetime_decls_helper(visitor, &function_declaration.lifetimes);
+ walk_fn_decl(visitor, &function_declaration.decl);
+ walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes);
}
TyPath(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself {
visitor.visit_path(path, typ.id);
}
TyObjectSum(ref ty, ref bounds) => {
- visitor.visit_ty(&**ty);
- walk_ty_param_bounds_helper(visitor, bounds);
+ visitor.visit_ty(ty);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
}
TyFixedLengthVec(ref ty, ref expression) => {
- visitor.visit_ty(&**ty);
- visitor.visit_expr(&**expression)
+ visitor.visit_ty(ty);
+ visitor.visit_expr(expression)
}
TyPolyTraitRef(ref bounds) => {
- walk_ty_param_bounds_helper(visitor, bounds)
+ walk_list!(visitor, visit_ty_param_bound, bounds);
}
TyTypeof(ref expression) => {
- visitor.visit_expr(&**expression)
+ visitor.visit_expr(expression)
}
TyInfer => {}
TyMac(ref mac) => {
}
}
-pub fn walk_lifetime_decls_helper<'v, V: Visitor<'v>>(visitor: &mut V,
- lifetimes: &'v Vec<LifetimeDef>) {
- for l in lifetimes {
- visitor.visit_lifetime_def(l);
- }
-}
-
pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) {
for segment in &path.segments {
visitor.visit_path_segment(path.span, segment);
}
}
+pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V, prefix: &'v Path,
+ item: &'v PathListItem) {
+ for segment in &prefix.segments {
+ visitor.visit_path_segment(prefix.span, segment);
+ }
+
+ walk_opt_ident(visitor, item.span, item.node.name());
+ walk_opt_ident(visitor, item.span, item.node.rename());
+}
+
pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
path_span: Span,
segment: &'v PathSegment) {
_path_span: Span,
path_parameters: &'v PathParameters) {
match *path_parameters {
- ast::AngleBracketedParameters(ref data) => {
- for typ in data.types.iter() {
- visitor.visit_ty(&**typ);
- }
- for lifetime in &data.lifetimes {
- visitor.visit_lifetime_ref(lifetime);
- }
- for binding in data.bindings.iter() {
- visitor.visit_assoc_type_binding(&**binding);
- }
+ AngleBracketedParameters(ref data) => {
+ walk_list!(visitor, visit_ty, &data.types);
+ walk_list!(visitor, visit_lifetime, &data.lifetimes);
+ walk_list!(visitor, visit_assoc_type_binding, &data.bindings);
}
- ast::ParenthesizedParameters(ref data) => {
- for typ in &data.inputs {
- visitor.visit_ty(&**typ);
- }
- if let Some(ref typ) = data.output {
- visitor.visit_ty(&**typ);
- }
+ ParenthesizedParameters(ref data) => {
+ walk_list!(visitor, visit_ty, &data.inputs);
+ walk_list!(visitor, visit_ty, &data.output);
}
}
}
pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V,
type_binding: &'v TypeBinding) {
visitor.visit_ident(type_binding.span, type_binding.ident);
- visitor.visit_ty(&*type_binding.ty);
+ visitor.visit_ty(&type_binding.ty);
}
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
match pattern.node {
- PatEnum(ref path, ref children) => {
+ PatEnum(ref path, ref opt_children) => {
visitor.visit_path(path, pattern.id);
- if let Some(ref children) = *children {
- for child in children {
- visitor.visit_pat(&*child)
- }
+ if let Some(ref children) = *opt_children {
+ walk_list!(visitor, visit_pat, children);
}
}
PatQPath(ref qself, ref path) => {
PatStruct(ref path, ref fields, _) => {
visitor.visit_path(path, pattern.id);
for field in fields {
- visitor.visit_pat(&*field.node.pat)
+ visitor.visit_ident(field.span, field.node.ident);
+ visitor.visit_pat(&field.node.pat)
}
}
PatTup(ref tuple_elements) => {
- for tuple_element in tuple_elements {
- visitor.visit_pat(&**tuple_element)
- }
+ walk_list!(visitor, visit_pat, tuple_elements);
}
PatBox(ref subpattern) |
PatRegion(ref subpattern, _) => {
- visitor.visit_pat(&**subpattern)
+ visitor.visit_pat(subpattern)
}
PatIdent(_, ref pth1, ref optional_subpattern) => {
visitor.visit_ident(pth1.span, pth1.node);
- match *optional_subpattern {
- None => {}
- Some(ref subpattern) => visitor.visit_pat(&**subpattern),
- }
+ walk_list!(visitor, visit_pat, optional_subpattern);
}
- PatLit(ref expression) => visitor.visit_expr(&**expression),
+ PatLit(ref expression) => visitor.visit_expr(expression),
PatRange(ref lower_bound, ref upper_bound) => {
- visitor.visit_expr(&**lower_bound);
- visitor.visit_expr(&**upper_bound)
+ visitor.visit_expr(lower_bound);
+ visitor.visit_expr(upper_bound)
}
PatWild(_) => (),
- PatVec(ref prepattern, ref slice_pattern, ref postpatterns) => {
- for prepattern in prepattern {
- visitor.visit_pat(&**prepattern)
- }
- if let Some(ref slice_pattern) = *slice_pattern {
- visitor.visit_pat(&**slice_pattern)
- }
- for postpattern in postpatterns {
- visitor.visit_pat(&**postpattern)
- }
+ PatVec(ref prepatterns, ref slice_pattern, ref postpatterns) => {
+ walk_list!(visitor, visit_pat, prepatterns);
+ walk_list!(visitor, visit_pat, slice_pattern);
+ walk_list!(visitor, visit_pat, postpatterns);
}
PatMac(ref mac) => visitor.visit_mac(mac),
}
match foreign_item.node {
ForeignItemFn(ref function_declaration, ref generics) => {
- walk_fn_decl(visitor, &**function_declaration);
+ walk_fn_decl(visitor, function_declaration);
visitor.visit_generics(generics)
}
- ForeignItemStatic(ref typ, _) => visitor.visit_ty(&**typ),
- }
-
- for attr in &foreign_item.attrs {
- visitor.visit_attribute(attr);
+ ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
}
-}
-pub fn walk_ty_param_bounds_helper<'v, V: Visitor<'v>>(visitor: &mut V,
- bounds: &'v OwnedSlice<TyParamBound>) {
- for bound in bounds.iter() {
- visitor.visit_ty_param_bound(bound)
- }
+ walk_list!(visitor, visit_attribute, &foreign_item.attrs);
}
pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V,
visitor.visit_poly_trait_ref(typ, modifier);
}
RegionTyParamBound(ref lifetime) => {
- visitor.visit_lifetime_bound(lifetime);
+ visitor.visit_lifetime(lifetime);
}
}
}
pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) {
- for param in generics.ty_params.iter() {
+ for param in &generics.ty_params {
visitor.visit_ident(param.span, param.ident);
- walk_ty_param_bounds_helper(visitor, ¶m.bounds);
- walk_ty_opt(visitor, ¶m.default);
+ walk_list!(visitor, visit_ty_param_bound, ¶m.bounds);
+ walk_list!(visitor, visit_ty, ¶m.default);
}
- walk_lifetime_decls_helper(visitor, &generics.lifetimes);
+ walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
for predicate in &generics.where_clause.predicates {
match predicate {
- &ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate{ref bounded_ty,
+ &WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
ref bounds,
+ ref bound_lifetimes,
..}) => {
- visitor.visit_ty(&**bounded_ty);
- walk_ty_param_bounds_helper(visitor, bounds);
+ visitor.visit_ty(bounded_ty);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
}
- &ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate{ref lifetime,
+ &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
ref bounds,
..}) => {
- visitor.visit_lifetime_ref(lifetime);
-
- for bound in bounds {
- visitor.visit_lifetime_ref(bound);
- }
+ visitor.visit_lifetime(lifetime);
+ walk_list!(visitor, visit_lifetime, bounds);
}
- &ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{id,
+ &WherePredicate::EqPredicate(WhereEqPredicate{id,
ref path,
ref ty,
..}) => {
visitor.visit_path(path, id);
- visitor.visit_ty(&**ty);
+ visitor.visit_ty(ty);
}
}
}
pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FunctionRetTy) {
if let Return(ref output_ty) = *ret_ty {
- visitor.visit_ty(&**output_ty)
+ visitor.visit_ty(output_ty)
}
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
for argument in &function_declaration.inputs {
- visitor.visit_pat(&*argument.pat);
- visitor.visit_ty(&*argument.ty)
+ visitor.visit_pat(&argument.pat);
+ visitor.visit_ty(&argument.ty)
}
walk_fn_ret_ty(visitor, &function_declaration.output)
}
-pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
- function_kind: FnKind<'v>,
- function_declaration: &'v FnDecl,
- function_body: &'v Block,
- _span: Span) {
- walk_fn_decl(visitor, function_declaration);
-
+pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V,
+ function_kind: FnKind<'v>) {
match function_kind {
FnKind::ItemFn(_, generics, _, _, _, _) => {
visitor.visit_generics(generics);
visitor.visit_generics(&sig.generics);
visitor.visit_explicit_self(&sig.explicit_self);
}
- FnKind::Closure(..) => {}
+ FnKind::Closure => {}
}
+}
+pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
+ function_kind: FnKind<'v>,
+ function_declaration: &'v FnDecl,
+ function_body: &'v Block,
+ _span: Span) {
+ walk_fn_decl(visitor, function_declaration);
+ walk_fn_kind(visitor, function_kind);
visitor.visit_block(function_body)
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
visitor.visit_ident(trait_item.span, trait_item.ident);
- for attr in &trait_item.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_list!(visitor, visit_attribute, &trait_item.attrs);
match trait_item.node {
ConstTraitItem(ref ty, ref default) => {
visitor.visit_ty(ty);
- if let Some(ref expr) = *default {
- visitor.visit_expr(expr);
- }
+ walk_list!(visitor, visit_expr, default);
}
MethodTraitItem(ref sig, None) => {
visitor.visit_explicit_self(&sig.explicit_self);
body, trait_item.span, trait_item.id);
}
TypeTraitItem(ref bounds, ref default) => {
- walk_ty_param_bounds_helper(visitor, bounds);
- walk_ty_opt(visitor, default);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_ty, default);
}
}
}
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
visitor.visit_ident(impl_item.span, impl_item.ident);
- for attr in &impl_item.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_list!(visitor, visit_attribute, &impl_item.attrs);
match impl_item.node {
ConstImplItem(ref ty, ref expr) => {
visitor.visit_ty(ty);
}
pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V,
- struct_definition: &'v StructDef) {
- for field in &struct_definition.fields {
- visitor.visit_struct_field(field)
- }
+ struct_definition: &'v VariantData) {
+ walk_list!(visitor, visit_struct_field, struct_definition.fields());
}
pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V,
struct_field: &'v StructField) {
- if let NamedField(name, _) = struct_field.node.kind {
- visitor.visit_ident(struct_field.span, name);
- }
-
- visitor.visit_ty(&*struct_field.node.ty);
-
- for attr in &struct_field.node.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_opt_ident(visitor, struct_field.span, struct_field.node.ident());
+ visitor.visit_ty(&struct_field.node.ty);
+ walk_list!(visitor, visit_attribute, &struct_field.node.attrs);
}
pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) {
- for statement in &block.stmts {
- visitor.visit_stmt(&**statement)
- }
- walk_expr_opt(visitor, &block.expr)
+ walk_list!(visitor, visit_stmt, &block.stmts);
+ walk_list!(visitor, visit_expr, &block.expr);
}
pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) {
match statement.node {
- StmtDecl(ref declaration, _) => visitor.visit_decl(&**declaration),
+ StmtDecl(ref declaration, _) => visitor.visit_decl(declaration),
StmtExpr(ref expression, _) | StmtSemi(ref expression, _) => {
- visitor.visit_expr(&**expression)
+ visitor.visit_expr(expression)
}
- StmtMac(ref mac, _) => visitor.visit_mac(&**mac),
+ StmtMac(ref mac, _) => visitor.visit_mac(mac),
}
}
pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) {
match declaration.node {
- DeclLocal(ref local) => visitor.visit_local(&**local),
- DeclItem(ref item) => visitor.visit_item(&**item),
- }
-}
-
-pub fn walk_expr_opt<'v, V: Visitor<'v>>(visitor: &mut V,
- optional_expression: &'v Option<P<Expr>>) {
- match *optional_expression {
- None => {}
- Some(ref expression) => visitor.visit_expr(&**expression),
- }
-}
-
-pub fn walk_exprs<'v, V: Visitor<'v>>(visitor: &mut V, expressions: &'v [P<Expr>]) {
- for expression in expressions {
- visitor.visit_expr(&**expression)
+ DeclLocal(ref local) => visitor.visit_local(local),
+ DeclItem(ref item) => visitor.visit_item(item),
}
}
pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
match expression.node {
- ExprBox(ref place, ref subexpression) => {
- place.as_ref().map(|e|visitor.visit_expr(&**e));
- visitor.visit_expr(&**subexpression)
+ ExprBox(ref subexpression) => {
+ visitor.visit_expr(subexpression)
+ }
+ ExprInPlace(ref place, ref subexpression) => {
+ visitor.visit_expr(place);
+ visitor.visit_expr(subexpression)
}
ExprVec(ref subexpressions) => {
- walk_exprs(visitor, subexpressions)
+ walk_list!(visitor, visit_expr, subexpressions);
}
ExprRepeat(ref element, ref count) => {
- visitor.visit_expr(&**element);
- visitor.visit_expr(&**count)
+ visitor.visit_expr(element);
+ visitor.visit_expr(count)
}
ExprStruct(ref path, ref fields, ref optional_base) => {
visitor.visit_path(path, expression.id);
for field in fields {
- visitor.visit_expr(&*field.expr)
+ visitor.visit_ident(field.ident.span, field.ident.node);
+ visitor.visit_expr(&field.expr)
}
- walk_expr_opt(visitor, optional_base)
+ walk_list!(visitor, visit_expr, optional_base);
}
ExprTup(ref subexpressions) => {
- for subexpression in subexpressions {
- visitor.visit_expr(&**subexpression)
- }
+ walk_list!(visitor, visit_expr, subexpressions);
}
ExprCall(ref callee_expression, ref arguments) => {
- for argument in arguments {
- visitor.visit_expr(&**argument)
- }
- visitor.visit_expr(&**callee_expression)
+ walk_list!(visitor, visit_expr, arguments);
+ visitor.visit_expr(callee_expression)
}
- ExprMethodCall(_, ref types, ref arguments) => {
- walk_exprs(visitor, arguments);
- for typ in types {
- visitor.visit_ty(&**typ)
- }
+ ExprMethodCall(ref ident, ref types, ref arguments) => {
+ visitor.visit_ident(ident.span, ident.node);
+ walk_list!(visitor, visit_expr, arguments);
+ walk_list!(visitor, visit_ty, types);
}
ExprBinary(_, ref left_expression, ref right_expression) => {
- visitor.visit_expr(&**left_expression);
- visitor.visit_expr(&**right_expression)
+ visitor.visit_expr(left_expression);
+ visitor.visit_expr(right_expression)
}
ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => {
- visitor.visit_expr(&**subexpression)
+ visitor.visit_expr(subexpression)
}
ExprLit(_) => {}
ExprCast(ref subexpression, ref typ) => {
- visitor.visit_expr(&**subexpression);
- visitor.visit_ty(&**typ)
+ visitor.visit_expr(subexpression);
+ visitor.visit_ty(typ)
}
ExprIf(ref head_expression, ref if_block, ref optional_else) => {
- visitor.visit_expr(&**head_expression);
- visitor.visit_block(&**if_block);
- walk_expr_opt(visitor, optional_else)
+ visitor.visit_expr(head_expression);
+ visitor.visit_block(if_block);
+ walk_list!(visitor, visit_expr, optional_else);
}
- ExprWhile(ref subexpression, ref block, _) => {
- visitor.visit_expr(&**subexpression);
- visitor.visit_block(&**block)
+ ExprWhile(ref subexpression, ref block, opt_ident) => {
+ visitor.visit_expr(subexpression);
+ visitor.visit_block(block);
+ walk_opt_ident(visitor, expression.span, opt_ident)
}
ExprIfLet(ref pattern, ref subexpression, ref if_block, ref optional_else) => {
- visitor.visit_pat(&**pattern);
- visitor.visit_expr(&**subexpression);
- visitor.visit_block(&**if_block);
- walk_expr_opt(visitor, optional_else);
- }
- ExprWhileLet(ref pattern, ref subexpression, ref block, _) => {
- visitor.visit_pat(&**pattern);
- visitor.visit_expr(&**subexpression);
- visitor.visit_block(&**block);
- }
- ExprForLoop(ref pattern, ref subexpression, ref block, _) => {
- visitor.visit_pat(&**pattern);
- visitor.visit_expr(&**subexpression);
- visitor.visit_block(&**block)
- }
- ExprLoop(ref block, _) => visitor.visit_block(&**block),
- ExprMatch(ref subexpression, ref arms, _) => {
- visitor.visit_expr(&**subexpression);
- for arm in arms {
- visitor.visit_arm(arm)
- }
+ visitor.visit_pat(pattern);
+ visitor.visit_expr(subexpression);
+ visitor.visit_block(if_block);
+ walk_list!(visitor, visit_expr, optional_else);
+ }
+ ExprWhileLet(ref pattern, ref subexpression, ref block, opt_ident) => {
+ visitor.visit_pat(pattern);
+ visitor.visit_expr(subexpression);
+ visitor.visit_block(block);
+ walk_opt_ident(visitor, expression.span, opt_ident)
+ }
+ ExprForLoop(ref pattern, ref subexpression, ref block, opt_ident) => {
+ visitor.visit_pat(pattern);
+ visitor.visit_expr(subexpression);
+ visitor.visit_block(block);
+ walk_opt_ident(visitor, expression.span, opt_ident)
+ }
+ ExprLoop(ref block, opt_ident) => {
+ visitor.visit_block(block);
+ walk_opt_ident(visitor, expression.span, opt_ident)
+ }
+ ExprMatch(ref subexpression, ref arms) => {
+ visitor.visit_expr(subexpression);
+ walk_list!(visitor, visit_arm, arms);
}
ExprClosure(_, ref function_declaration, ref body) => {
visitor.visit_fn(FnKind::Closure,
- &**function_declaration,
- &**body,
+ function_declaration,
+ body,
expression.span,
expression.id)
}
- ExprBlock(ref block) => visitor.visit_block(&**block),
+ ExprBlock(ref block) => visitor.visit_block(block),
ExprAssign(ref left_hand_expression, ref right_hand_expression) => {
- visitor.visit_expr(&**right_hand_expression);
- visitor.visit_expr(&**left_hand_expression)
+ visitor.visit_expr(right_hand_expression);
+ visitor.visit_expr(left_hand_expression)
}
ExprAssignOp(_, ref left_expression, ref right_expression) => {
- visitor.visit_expr(&**right_expression);
- visitor.visit_expr(&**left_expression)
+ visitor.visit_expr(right_expression);
+ visitor.visit_expr(left_expression)
}
- ExprField(ref subexpression, _) => {
- visitor.visit_expr(&**subexpression);
+ ExprField(ref subexpression, ref ident) => {
+ visitor.visit_expr(subexpression);
+ visitor.visit_ident(ident.span, ident.node);
}
ExprTupField(ref subexpression, _) => {
- visitor.visit_expr(&**subexpression);
+ visitor.visit_expr(subexpression);
}
ExprIndex(ref main_expression, ref index_expression) => {
- visitor.visit_expr(&**main_expression);
- visitor.visit_expr(&**index_expression)
+ visitor.visit_expr(main_expression);
+ visitor.visit_expr(index_expression)
}
ExprRange(ref start, ref end) => {
- walk_expr_opt(visitor, start);
- walk_expr_opt(visitor, end)
+ walk_list!(visitor, visit_expr, start);
+ walk_list!(visitor, visit_expr, end);
}
ExprPath(ref maybe_qself, ref path) => {
if let Some(ref qself) = *maybe_qself {
}
visitor.visit_path(path, expression.id)
}
- ExprBreak(_) | ExprAgain(_) => {}
+ ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => {
+ for sp_ident in opt_sp_ident {
+ visitor.visit_ident(sp_ident.span, sp_ident.node);
+ }
+ }
ExprRet(ref optional_expression) => {
- walk_expr_opt(visitor, optional_expression)
+ walk_list!(visitor, visit_expr, optional_expression);
}
ExprMac(ref mac) => visitor.visit_mac(mac),
ExprParen(ref subexpression) => {
- visitor.visit_expr(&**subexpression)
+ visitor.visit_expr(subexpression)
}
ExprInlineAsm(ref ia) => {
- for input in &ia.inputs {
- let (_, ref input) = *input;
- visitor.visit_expr(&**input)
+ for &(_, ref input) in &ia.inputs {
+ visitor.visit_expr(&input)
}
- for output in &ia.outputs {
- let (_, ref output, _) = *output;
- visitor.visit_expr(&**output)
+ for &(_, ref output, _) in &ia.outputs {
+ visitor.visit_expr(&output)
}
}
}
}
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
- for pattern in &arm.pats {
- visitor.visit_pat(&**pattern)
- }
- walk_expr_opt(visitor, &arm.guard);
- visitor.visit_expr(&*arm.body);
- for attr in &arm.attrs {
- visitor.visit_attribute(attr);
- }
+ walk_list!(visitor, visit_pat, &arm.pats);
+ walk_list!(visitor, visit_expr, &arm.guard);
+ visitor.visit_expr(&arm.body);
+ walk_list!(visitor, visit_attribute, &arm.attrs);
}
#![deny(missing_docs)]
#![feature(box_syntax)]
-#![feature(path_ext)]
#![feature(rustc_private)]
#![feature(staged_api)]
#![feature(str_char)]
fn x(t: &str) -> String {
let p = get_dbpath_for_term(t).expect("no terminfo entry found");
p.to_str().unwrap().to_string()
- };
+ }
assert!(x("screen") == "/usr/share/terminfo/s/screen");
assert!(get_dbpath_for_term("") == None);
env::set_var("TERMINFO_DIRS", ":");
} else {
None
}
- };
+ }
filtered.into_iter().filter_map(filter).collect()
};
if (data.show_time) {
double elapsed;
- if (t1 == -1 || t2 == -1) {
+ if (t1 == ((clock_t) -1) || t2 == ((clock_t) -1)) {
fprintf(stderr, "Failed to get the time.\n");
return 1;
}
}
/* not a well-formed codespan; use found matching emph char */
- if (i >= size) return tmp_i;
+ if (bt < span_nb && i >= size) return tmp_i;
}
/* skipping a link */
else if (data[i] == '[') {
* CONSTANTS *
*************/
-#define HOEDOWN_VERSION "3.0.4"
+#define HOEDOWN_VERSION "3.0.5"
#define HOEDOWN_VERSION_MAJOR 3
#define HOEDOWN_VERSION_MINOR 0
-#define HOEDOWN_VERSION_REVISION 4
+#define HOEDOWN_VERSION_REVISION 5
/*************
uint64_t get_z(struct S s) {
return s.z;
}
+
+uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) {
+ return f.c;
+}
use book;
use book::{Book, BookItem};
-use javascript;
-
use rustdoc;
struct Build;
}
fn render(book: &Book, tgt: &Path) -> CliResult<()> {
- let tmp = try!(TempDir::new("rust-book"));
+ let tmp = try!(TempDir::new("rustbook"));
for (_section, item) in book.iter() {
let out_path = match item.path.parent() {
// write the prelude to a temporary HTML file for rustdoc inclusion
let prelude = tmp.path().join("prelude.html");
{
- let mut toc = BufWriter::new(try!(File::create(&prelude)));
- try!(writeln!(&mut toc, r#"<div id="nav">
- <button id="toggle-nav">
- <span class="sr-only">Toggle navigation</span>
- <span class="bar"></span>
- <span class="bar"></span>
- <span class="bar"></span>
- </button>
- </div>"#));
- let _ = write_toc(book, &item, &mut toc);
- try!(writeln!(&mut toc, "<div id='page-wrapper'>"));
- try!(writeln!(&mut toc, "<div id='page'>"));
+ let mut buffer = BufWriter::new(try!(File::create(&prelude)));
+ try!(writeln!(&mut buffer, r#"
+ <div id="nav">
+ <button id="toggle-nav">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="bar"></span>
+ <span class="bar"></span>
+ <span class="bar"></span>
+ </button>
+ </div>"#));
+ let _ = write_toc(book, &item, &mut buffer);
+ try!(writeln!(&mut buffer, "<div id='page-wrapper'>"));
+ try!(writeln!(&mut buffer, "<div id='page'>"));
}
// write the postlude to a temporary HTML file for rustdoc inclusion
let postlude = tmp.path().join("postlude.html");
{
- let mut toc = BufWriter::new(try!(File::create(&postlude)));
- try!(toc.write_all(javascript::JAVASCRIPT.as_bytes()));
- try!(writeln!(&mut toc, "</div></div>"));
+ let mut buffer = BufWriter::new(try!(File::create(&postlude)));
+ try!(writeln!(&mut buffer, "<script src='rustbook.js'></script>"));
+ try!(writeln!(&mut buffer, "<script src='playpen.js'></script>"));
+ try!(writeln!(&mut buffer, "</div></div>"));
}
try!(fs::create_dir_all(&out_path));
format!("--html-before-content={}", prelude.display()),
format!("--html-after-content={}", postlude.display()),
format!("--markdown-playground-url=https://play.rust-lang.org"),
- format!("--markdown-css={}", item.path_to_root.join("rust-book.css").display()),
+ format!("--markdown-css={}", item.path_to_root.join("rustbook.css").display()),
"--markdown-no-toc".to_string(),
];
let output_result = rustdoc::main_args(rustdoc_args);
let css = include_bytes!("static/rustbook.css");
let js = include_bytes!("static/rustbook.js");
- let mut css_file = try!(File::create(tgt.join("rust-book.css")));
+ let mut css_file = try!(File::create(tgt.join("rustbook.css")));
try!(css_file.write_all(css));
- let mut js_file = try!(File::create(tgt.join("rust-book.js")));
+ let mut js_file = try!(File::create(tgt.join("rustbook.js")));
try!(js_file.write_all(js));
}
pub fn usage() {
- println!("Usage: rust-book <command> [<args>]");
+ println!("Usage: rustbook <command> [<args>]");
println!("");
println!("The <command> must be one of:");
println!(" help Print this message.");
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// The rust-book JavaScript in string form.
-
-pub static JAVASCRIPT: &'static str = r#"
-<script type="text/javascript" src="rust-book.js"></script>
-<script type="text/javascript" src="playpen.js"></script>
-"#;
mod serve;
mod test;
-mod javascript;
-
static EXIT_STATUS: AtomicIsize = ATOMIC_ISIZE_INIT;
-#[cfg(not(test))] // thanks #12327
fn main() {
let mut term = Term::new();
let cmd: Vec<_> = env::args().collect();
/**
- * Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+ * Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
* http://rust-lang.org/COPYRIGHT.
*
* except according to those terms.
*/
-@import url("../rust.css");
+@import url('../rust.css');
body {
- max-width:none;
- font: 16px/1.4 'Source Serif Pro', Georgia, Times, 'Times New Roman', serif;
- line-height: 1.6;
+ max-width: none;
+ font: 16px/1.6 'Source Serif Pro', Georgia, Times, 'Times New Roman', serif;
color: #333;
}
@media only screen {
#toc {
position: fixed;
- left: 0px;
- top: 0px;
- bottom: 0px;
+ top: 0;
+ left: 0;
+ bottom: 0;
width: 300px;
overflow-y: auto;
- border-right: 1px solid rgba(0, 0, 0, 0.07);
- padding: 10px 10px;
+ border-right: 1px solid #e8e8e8;
+ padding: 0 15px;
font-size: 14px;
- box-sizing: border-box;
- -webkit-overflow-scrolling: touch;
background-color: #fafafa;
- color: #364149;
+ -webkit-overflow-scrolling: touch;
}
#page-wrapper {
position: absolute;
- left: 310px;
- right: 0px;
- top: 0px;
- box-sizing: border-box;
- background: none repeat scroll 0% 0% #FFF;
+ top: 0;
+ left: 300px;
+ right: 0;
+ padding: 0 15px;
-webkit-overflow-scrolling: touch;
}
}
@media only print {
- #toc, #nav, #menu-bar {
+ #toc, #nav {
display: none;
}
}
-@media only screen and (max-width: 1060px) {
+@media only screen and (max-width: 1023px) {
#toc {
width: 100%;
- margin-right: 0;
top: 40px;
}
+
#page-wrapper {
top: 40px;
- left: 15px;
- padding-right: 15px;
+ left: 0;
}
+
.mobile-hidden {
display: none;
}
}
#page {
- margin-left: auto;
- margin-right:auto;
+ margin: 0 auto;
max-width: 750px;
padding-bottom: 50px;
}
.chapter {
- list-style: none outside none;
- padding-left: 0px;
+ list-style: none;
+ padding-left: 0;
line-height: 30px;
}
.section {
- list-style: none outside none;
+ list-style: none;
padding-left: 20px;
line-height: 40px;
}
padding: 5px 0;
}
-.chapter li a.active {
- color: #008cff;
-}
-
+.chapter li a.active,
.chapter li a:hover {
color: #008cff;
text-decoration: none;
}
#toggle-nav {
- height: 20px;
- width: 30px;
- padding: 3px 3px 0 3px;
-}
-
-#toggle-nav {
+ cursor: pointer;
margin-top: 5px;
width: 30px;
height: 30px;
- background-color: #FFF;
+ background-color: #fff;
border: 1px solid #666;
- border-radius: 3px 3px 3px 3px;
+ border-radius: 3px;
+ padding: 3px 3px 0 3px;
}
.sr-only {
}
pre {
- padding: 16px;
+ padding: 11px;
overflow: auto;
font-size: 85%;
line-height: 1.45;
border-radius: 3px;
}
-.nav-previous-next {
- margin-top: 60px;
-}
-
.left {
float: left;
}
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+/*jslint browser: true, es5: true */
+/*globals $: true, rootPath: true */
-document.addEventListener("DOMContentLoaded", function(event) {
+document.addEventListener('DOMContentLoaded', function() {
+ 'use strict';
- document.getElementById("toggle-nav").onclick = toggleNav;
+ document.getElementById('toggle-nav').onclick = function(e) {
+ var toc = document.getElementById('toc');
+ var pagewrapper = document.getElementById('page-wrapper');
+ toggleClass(toc, 'mobile-hidden');
+ toggleClass(pagewrapper, 'mobile-hidden');
+ };
- function toggleNav() {
- var toc = document.getElementById("toc");
- var pagewrapper = document.getElementById("page-wrapper");
- toggleClass(toc, "mobile-hidden");
- toggleClass(pagewrapper, "mobile-hidden");
- }
+ function toggleClass(el, className) {
+ // from http://youmightnotneedjquery.com/
+ if (el.classList) {
+ el.classList.toggle(className);
+ } else {
+ var classes = el.className.split(' ');
+ var existingIndex = classes.indexOf(className);
- function toggleClass(el, className) {
- // from http://youmightnotneedjquery.com/
- if (el.classList) {
- el.classList.toggle(className);
- } else {
- var classes = el.className.split(' ');
- var existingIndex = classes.indexOf(className);
+ if (existingIndex >= 0) {
+ classes.splice(existingIndex, 1);
+ } else {
+ classes.push(className);
+ }
- if (existingIndex >= 0) {
- classes.splice(existingIndex, 1);
- } else {
- classes.push(className);
- }
-
- el.className = classes.join(' ');
- }
- }
+ el.className = classes.join(' ');
+ }
+ }
- // The below code is used to add prev and next navigation links to the bottom
- // of each of the sections.
- // It works by extracting the current page based on the url and iterates over
- // the menu links until it finds the menu item for the current page. We then
- // create a copy of the preceding and following menu links and add the
- // correct css class and insert them into the bottom of the page.
- var toc = document.getElementById('toc').getElementsByTagName('a');
- var href = document.location.pathname.split('/').pop();
- if (href === 'index.html' || href === '') {
- href = 'README.html';
- }
+ // The below code is used to add prev and next navigation links to the
+ // bottom of each of the sections.
+ // It works by extracting the current page based on the url and iterates
+ // over the menu links until it finds the menu item for the current page. We
+ // then create a copy of the preceding and following menu links and add the
+ // correct css class and insert them into the bottom of the page.
+ var toc = document.getElementById('toc').getElementsByTagName('a');
+ var href = document.location.pathname.split('/').pop();
- for (var i = 0; i < toc.length; i++) {
- if (toc[i].attributes.href.value.split('/').pop() === href) {
- var nav = document.createElement('p');
- if (i > 0) {
- var prevNode = toc[i-1].cloneNode(true);
- prevNode.className = 'left';
- prevNode.setAttribute('rel', 'prev');
- nav.appendChild(prevNode);
- }
- if (i < toc.length - 1) {
- var nextNode = toc[i+1].cloneNode(true);
- nextNode.className = 'right';
- nextNode.setAttribute('rel', 'next');
- nav.appendChild(nextNode);
- }
- document.getElementById('page').appendChild(nav);
- break;
+ if (href === 'index.html' || href === '') {
+ href = 'README.html';
}
- }
+ for (var i = 0; i < toc.length; i++) {
+ if (toc[i].attributes.href.value.split('/').pop() === href) {
+ var nav = document.createElement('p');
+
+ if (i > 0) {
+ var prevNode = toc[i-1].cloneNode(true);
+ prevNode.className = 'left';
+ prevNode.setAttribute('rel', 'prev');
+ nav.appendChild(prevNode);
+ }
+
+ if (i < toc.length - 1) {
+ var nextNode = toc[i+1].cloneNode(true);
+ nextNode.className = 'right';
+ nextNode.setAttribute('rel', 'next');
+ nav.appendChild(nextNode);
+ }
+
+ document.getElementById('page').appendChild(nav);
+
+ break;
+ }
+ }
});
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Common API for all rust-book subcommands.
+//! Common API for all rustbook subcommands.
use error::CliResult;
use error::CommandResult;
auto Member = NewMembers[i];
assert(Member->name);
if (Member->filename) {
+#if LLVM_VERSION_MINOR >= 8
+ Members.push_back(NewArchiveIterator(Member->filename));
+#else
Members.push_back(NewArchiveIterator(Member->filename, Member->name));
+#endif
} else {
Members.push_back(NewArchiveIterator(Member->child, Member->name));
}
}
+#if LLVM_VERSION_MINOR >= 8
+ auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true, false);
+#else
auto pair = writeArchive(Dst, Members, WriteSymbtab, Kind, true);
+#endif
if (!pair.second)
return 0;
LLVMRustSetLastError(pair.second.message().c_str());
initializeVectorization(Registry);
initializeIPO(Registry);
initializeAnalysis(Registry);
+#if LLVM_VERSION_MINOR <= 7
initializeIPA(Registry);
+#endif
initializeTransformUtils(Registry);
initializeInstCombine(Registry);
initializeInstrumentation(Registry);
#endif
PM->run(*unwrap(M));
- // Apparently `addPassesToEmitFile` adds an pointer to our on-the-stack output
+ // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output
// stream (OS), so the only real safe place to delete this is here? Don't we
// wish this was written in Rust?
delete PM;
LLVMTargetMachineRef TMR) {
TargetMachine *Target = unwrap(TMR);
#if LLVM_VERSION_MINOR >= 7
- if (const DataLayout *DL = Target->getDataLayout())
- unwrap(Module)->setDataLayout(*DL);
+ unwrap(Module)->setDataLayout(Target->createDataLayout());
#elif LLVM_VERSION_MINOR >= 6
if (const DataLayout *DL = Target->getSubtargetImpl()->getDataLayout())
unwrap(Module)->setDataLayout(DL);
LLVMMetadataRef File,
LLVMMetadataRef ParameterTypes) {
return wrap(Builder->createSubroutineType(
+#if LLVM_VERSION_MINOR <= 7
unwrapDI<DIFile>(File),
+#endif
#if LLVM_VERSION_MINOR >= 7
DITypeRefArray(unwrap<MDTuple>(ParameterTypes))));
#elif LLVM_VERSION_MINOR >= 6
));
}
#endif
+#if LLVM_VERSION_MINOR >= 8
+ if (Tag == 0x100) { // DW_TAG_auto_variable
+ return wrap(Builder->createAutoVariable(
+ unwrapDI<DIDescriptor>(Scope), Name,
+ unwrapDI<DIFile>(File),
+ LineNo,
+ unwrapDI<DIType>(Ty), AlwaysPreserve, Flags));
+ } else {
+ return wrap(Builder->createParameterVariable(
+ unwrapDI<DIDescriptor>(Scope), Name, ArgNo,
+ unwrapDI<DIFile>(File),
+ LineNo,
+ unwrapDI<DIType>(Ty), AlwaysPreserve, Flags));
+ }
+#else
return wrap(Builder->createLocalVariable(Tag,
unwrapDI<DIDescriptor>(Scope), Name,
unwrapDI<DIFile>(File),
LineNo,
unwrapDI<DIType>(Ty), AlwaysPreserve, Flags, ArgNo));
+#endif
}
extern "C" LLVMMetadataRef LLVMDIBuilderCreateArrayType(
unsigned NumClauses,
const char* Name,
LLVMValueRef F) {
-#if LLVM_VERSION_MINOR >= 7
- unwrap<Function>(F)->setPersonalityFn(unwrap<Constant>(PersFn));
- return LLVMBuildLandingPad(Builder, Ty, NumClauses, Name);
-#else
return LLVMBuildLandingPad(Builder, Ty, PersFn, NumClauses, Name);
-#endif
}
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2015-09-11
+2015-12-02
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(augmented_assignments)]
+#![feature(op_assign_traits)]
+
+use std::ops::AddAssign;
+
+pub struct Int(i32);
+
+impl AddAssign<i32> for Int {
+ fn add_assign(&mut self, _: i32) {
+ unimplemented!();
+ }
+}
#![crate_type = "rlib"]
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// no-prefer-dynamic
#[unstable(feature = "test_feature", issue = "0")]
pub mod unstable_mod {
#[stable(feature = "test_feature", since = "1.0.0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated() {}
pub fn unstable() {}
pub fn f<T>() -> Box<i<T>+'static> {
impl<T> i<T> for () { }
- box() () as Box<i<T>+'static>
+ box () as Box<i<T>+'static>
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="lib"]
+
+pub mod foo {
+ pub use super::*;
+}
#[macro_use] extern crate rustc;
extern crate rustc_front;
+extern crate syntax;
-use rustc::lint::{Context, LintPass, LintPassObject, LintArray};
+use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
use rustc::plugin::Registry;
-use rustc_front::{hir, attr};
+use rustc_front::hir;
+use syntax::attr;
declare_lint!(CRATE_NOT_OKAY, Warn, "crate not marked with #![crate_okay]");
fn get_lints(&self) -> LintArray {
lint_array!(CRATE_NOT_OKAY)
}
+}
- fn check_crate(&mut self, cx: &Context, krate: &hir::Crate) {
+impl LateLintPass for Pass {
+ fn check_crate(&mut self, cx: &LateContext, krate: &hir::Crate) {
if !attr::contains_name(&krate.attrs, "crate_okay") {
cx.span_lint(CRATE_NOT_OKAY, krate.span,
"crate is not marked with #![crate_okay]");
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_lint_pass(box Pass as LintPassObject);
+ reg.register_late_lint_pass(box Pass as LateLintPassObject);
}
extern crate rustc;
use rustc_front::hir;
-use rustc::lint::{Context, LintPass, LintPassObject, LintArray};
+use rustc::lint::{LateContext, LintContext, LintPass, LateLintPass, LateLintPassObject, LintArray};
use rustc::plugin::Registry;
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
fn get_lints(&self) -> LintArray {
lint_array!(TEST_LINT, PLEASE_LINT)
}
+}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
- match &*it.ident.name.as_str() {
+impl LateLintPass for Pass {
+ fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
+ match &*it.name.as_str() {
"lintme" => cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"),
"pleaselintme" => cx.span_lint(PLEASE_LINT, it.span, "item is named 'pleaselintme'"),
_ => {}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_lint_pass(box Pass as LintPassObject);
+ reg.register_late_lint_pass(box Pass as LateLintPassObject);
reg.register_lint_group("lint_me", vec![TEST_LINT, PLEASE_LINT]);
}
#![unstable(feature = "test_feature", issue = "0")]
#[stable(feature = "test_feature", since = "1.0.0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub fn foo() -> usize {
20
}
#![feature(plugin_registrar)]
#![feature(box_syntax, rustc_private)]
-extern crate rustc_front;
+extern crate syntax;
// Load rustc as a plugin to get macros
#[macro_use]
extern crate rustc;
-use rustc::lint::{Context, LintPass, LintPassObject, LintArray};
+use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
+ EarlyLintPassObject, LintArray};
use rustc::plugin::Registry;
-use rustc_front::hir;
+use syntax::ast;
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
struct Pass;
fn get_lints(&self) -> LintArray {
lint_array!(TEST_LINT)
}
+}
- fn check_item(&mut self, cx: &Context, it: &hir::Item) {
- if it.ident.name == "lintme" {
+impl EarlyLintPass for Pass {
+ fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
+ if it.ident.name.as_str() == "lintme" {
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
}
}
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_lint_pass(box Pass as LintPassObject);
+ reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
}
#![stable(feature = "lint_stability", since = "1.0.0")]
#[stable(feature = "test_feature", since = "1.0.0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated() {}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated_text() {}
#[unstable(feature = "test_feature", issue = "0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated_unstable() {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable() {}
-#[stable(feature = "rust1", since = "1.0.0", reason = "text")]
+#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable_text() {}
#[stable(feature = "rust1", since = "1.0.0")]
impl MethodTester {
#[stable(feature = "test_feature", since = "1.0.0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated(&self) {}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated_text(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated_unstable(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable(&self) {}
- #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable_text(&self) {}
}
#[stable(feature = "test_feature", since = "1.0.0")]
pub trait Trait {
#[stable(feature = "test_feature", since = "1.0.0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated(&self) {}
#[stable(feature = "test_feature", since = "1.0.0")]
#[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated_text(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated_unstable(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable(&self) {}
- #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
+ #[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable_text(&self) {}
}
pub trait UnstableTrait { fn dummy(&self) { } }
#[stable(feature = "test_feature", since = "1.0.0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: isize
}
#[unstable(feature = "test_feature", issue = "0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnstableStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: isize
}
}
#[stable(feature = "test_feature", since = "1.0.0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "test_feature", issue = "0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnstableUnitStruct;
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableUnitStruct;
#[stable(feature = "test_feature", since = "1.0.0")]
pub enum Enum {
#[stable(feature = "test_feature", since = "1.0.0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
DeprecatedVariant,
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
DeprecatedUnstableVariant,
#[unstable(feature = "test_feature", issue = "0")]
UnstableVariant,
}
#[stable(feature = "test_feature", since = "1.0.0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "test_feature", issue = "0")]
-#[deprecated(since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableTupleStruct(#[stable(feature = "rust1", since = "1.0.0")] pub isize);
pub inherit: u8, // it's a lie (stable doesn't inherit)
#[unstable(feature = "test_feature", issue = "0")]
pub override1: u8,
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
pub override2: u8,
}
pub struct Stable2(#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")] pub u8);
+ #[deprecated(since = "1.0.0", reason = "text")] pub u8);
#[unstable(feature = "test_feature", issue = "0")]
pub struct Unstable {
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
pub override1: u8,
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
pub override2: u8,
}
pub struct Unstable2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")] pub u8);
+ #[deprecated(since = "1.0.0", reason = "text")] pub u8);
#[unstable(feature = "test_feature", issue = "0")]
-#[deprecated(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct Deprecated {
pub inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
}
#[unstable(feature = "test_feature", issue = "0")]
-#[deprecated(feature = "rust1", since = "1.0.0")]
+#[deprecated(since = "1.0.0", reason = "text")]
pub struct Deprecated2(pub u8,
#[stable(feature = "rust1", since = "1.0.0")] pub u8,
#[unstable(feature = "test_feature", issue = "0")] pub u8);
let mac_expr = match TokenTree::parse(cx, &mbe_matcher[..], args) {
Success(map) => {
- match (&*map[&str_to_ident("matched")], &*map[&str_to_ident("pat")]) {
+ match (&*map[&str_to_ident("matched").name], &*map[&str_to_ident("pat").name]) {
(&MatchedNonterminal(NtExpr(ref matched_expr)),
&MatchedSeq(ref pats, seq_sp)) => {
let pats: Vec<P<Pat>> = pats.iter().map(|pat_nt|
1200
}
-#[inline]
-pub static CCI_STATIC: usize = 34;
+pub const CCI_CONST: usize = 34;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[inline(never)]
pub static global: isize = 3;
-#[inline(never)]
static global0: isize = 4;
-#[inline(never)]
pub static global2: &'static isize = &global0;
pub fn verify_same(a: &'static isize) {
println!("{} keys", n_keys);
- // FIXME: #9970
- println!("{}", "\nBTreeMap:");
+ println!("\nBTreeMap:");
{
let mut map: BTreeMap<usize,usize> = BTreeMap::new();
vector(&mut map, n_keys, &rand);
}
- // FIXME: #9970
- println!("{}", "\nHashMap:");
+ println!("\nHashMap:");
{
let mut map: HashMap<usize,usize> = HashMap::new();
// OF THE POSSIBILITY OF SUCH DAMAGE.
use std::cmp::min;
-use std::env;
-use std::io;
-use std::io::prelude::*;
+use std::io::{self, Write};
+use std::sync::{Arc, Mutex};
+use std::thread;
+
const LINE_LEN: usize = 60;
+
+const BLOCK_LINES: usize = 512;
+const BLOCK_THOROUGHPUT: usize = LINE_LEN * BLOCK_LINES;
+const BLOCK_LEN: usize = BLOCK_THOROUGHPUT + BLOCK_LINES;
+
+const STDIN_BUF: usize = (LINE_LEN + 1) * 1024;
const LOOKUP_SIZE: usize = 4 * 1024;
const LOOKUP_SCALE: f32 = (LOOKUP_SIZE - 1) as f32;
-// Random number generator constants
-const IM: u32 = 139968;
-const IA: u32 = 3877;
-const IC: u32 = 29573;
-
-const ALU: &'static str = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTG\
- GGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGA\
- GACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAA\
- AATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAAT\
- CCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAAC\
- CCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTG\
- CACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
-
-const NULL_AMINO_ACID: AminoAcid = AminoAcid { c: ' ' as u8, p: 0.0 };
-
-static IUB: [AminoAcid;15] = [
- AminoAcid { c: 'a' as u8, p: 0.27 },
- AminoAcid { c: 'c' as u8, p: 0.12 },
- AminoAcid { c: 'g' as u8, p: 0.12 },
- AminoAcid { c: 't' as u8, p: 0.27 },
- AminoAcid { c: 'B' as u8, p: 0.02 },
- AminoAcid { c: 'D' as u8, p: 0.02 },
- AminoAcid { c: 'H' as u8, p: 0.02 },
- AminoAcid { c: 'K' as u8, p: 0.02 },
- AminoAcid { c: 'M' as u8, p: 0.02 },
- AminoAcid { c: 'N' as u8, p: 0.02 },
- AminoAcid { c: 'R' as u8, p: 0.02 },
- AminoAcid { c: 'S' as u8, p: 0.02 },
- AminoAcid { c: 'V' as u8, p: 0.02 },
- AminoAcid { c: 'W' as u8, p: 0.02 },
- AminoAcid { c: 'Y' as u8, p: 0.02 },
-];
-
-static HOMO_SAPIENS: [AminoAcid;4] = [
- AminoAcid { c: 'a' as u8, p: 0.3029549426680 },
- AminoAcid { c: 'c' as u8, p: 0.1979883004921 },
- AminoAcid { c: 'g' as u8, p: 0.1975473066391 },
- AminoAcid { c: 't' as u8, p: 0.3015094502008 },
-];
-
-fn sum_and_scale(a: &'static [AminoAcid]) -> Vec<AminoAcid> {
- let mut p = 0f32;
- let mut result: Vec<AminoAcid> = a.iter().map(|a_i| {
- p += a_i.p;
- AminoAcid { c: a_i.c, p: p * LOOKUP_SCALE }
- }).collect();
- let result_len = result.len();
- result[result_len - 1].p = LOOKUP_SCALE;
- result
-}
+const ALU: &'static [u8] =
+ b"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\
+ GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\
+ CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\
+ ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\
+ GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\
+ AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\
+ AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
+
+const IUB: &'static [(u8, f32)] =
+ &[(b'a', 0.27), (b'c', 0.12), (b'g', 0.12),
+ (b't', 0.27), (b'B', 0.02), (b'D', 0.02),
+ (b'H', 0.02), (b'K', 0.02), (b'M', 0.02),
+ (b'N', 0.02), (b'R', 0.02), (b'S', 0.02),
+ (b'V', 0.02), (b'W', 0.02), (b'Y', 0.02)];
+
+const HOMOSAPIENS: &'static [(u8, f32)] =
+ &[(b'a', 0.3029549426680),
+ (b'c', 0.1979883004921),
+ (b'g', 0.1975473066391),
+ (b't', 0.3015094502008)];
+
+// We need a specific Rng,
+// so implement this manually
+
+const MODULUS: u32 = 139968;
+const MULTIPLIER: u32 = 3877;
+const ADDITIVE: u32 = 29573;
+
+// Why doesn't rust already have this?
+// Algorithm directly taken from Wikipedia
+fn powmod(mut base: u64, mut exponent: u32, modulus: u64) -> u64 {
+ let mut ret = 1;
+ base %= modulus;
-#[derive(Copy, Clone)]
-struct AminoAcid {
- c: u8,
- p: f32,
+ while exponent > 0 {
+ if exponent & 1 == 1 {
+ ret *= base;
+ ret %= modulus;
+ }
+ exponent >>= 1;
+ base *= base;
+ base %= modulus;
+ }
+
+ ret
}
-struct RepeatFasta<'a, W:'a> {
- alu: &'static str,
- out: &'a mut W
+// Just a typical LCRNG
+pub struct Rng {
+ last: u32
}
-impl<'a, W: Write> RepeatFasta<'a, W> {
- fn new(alu: &'static str, w: &'a mut W) -> RepeatFasta<'a, W> {
- RepeatFasta { alu: alu, out: w }
+impl Rng {
+ pub fn new() -> Rng {
+ Rng { last: 42 }
}
- fn make(&mut self, n: usize) -> io::Result<()> {
- let alu_len = self.alu.len();
- let mut buf = vec![0; alu_len + LINE_LEN];
- let alu: &[u8] = self.alu.as_bytes();
+ pub fn max_value() -> u32 {
+ MODULUS - 1
+ }
- for (slot, val) in buf.iter_mut().zip(alu) {
- *slot = *val;
- }
- let buf_len = buf.len();
- for (slot, val) in buf[alu_len..buf_len].iter_mut().zip(&alu[..LINE_LEN]) {
- *slot = *val;
- }
+ pub fn normalize(p: f32) -> u32 {
+ (p * MODULUS as f32).floor() as u32
+ }
- let mut pos = 0;
- let mut bytes;
- let mut n = n;
- while n > 0 {
- bytes = min(LINE_LEN, n);
- try!(self.out.write_all(&buf[pos..pos + bytes]));
- try!(self.out.write_all(&[b'\n']));
- pos += bytes;
- if pos > alu_len {
- pos -= alu_len;
- }
- n -= bytes;
- }
- Ok(())
+ pub fn gen(&mut self) -> u32 {
+ self.last = (self.last * MULTIPLIER + ADDITIVE) % MODULUS;
+ self.last
}
-}
-fn make_lookup(a: &[AminoAcid]) -> [AminoAcid;LOOKUP_SIZE] {
- let mut lookup = [ NULL_AMINO_ACID;LOOKUP_SIZE ];
- let mut j = 0;
- for (i, slot) in lookup.iter_mut().enumerate() {
- while a[j].p < (i as f32) {
- j += 1;
- }
- *slot = a[j];
+ // This allows us to fast-forward the RNG,
+ // allowing us to run it in parallel.
+ pub fn future(&self, n: u32) -> Rng {
+ let a = MULTIPLIER as u64;
+ let b = ADDITIVE as u64;
+ let m = MODULUS as u64;
+
+ // (a^n - 1) mod (a-1) m
+ // x_k = ((a^n x_0 mod m) + --------------------- b) mod m
+ // a - 1
+ //
+ // Since (a - 1) divides (a^n - 1) mod (a-1) m,
+ // the subtraction does not overflow and thus can be non-modular.
+ //
+ let new_seed =
+ (powmod(a, n, m) * self.last as u64) % m +
+ (powmod(a, n, (a-1) * m) - 1) / (a-1) * b;
+
+ Rng { last: (new_seed % m) as u32 }
}
- lookup
}
-struct RandomFasta<'a, W:'a> {
- seed: u32,
- lookup: [AminoAcid;LOOKUP_SIZE],
- out: &'a mut W,
+
+// This will end up keeping track of threads, like
+// in the other multithreaded Rust version, in
+// order to keep writes in order.
+//
+// This is stolen from another multithreaded Rust
+// implementation, although that implementation
+// was not able to parallelize the RNG itself.
+struct BlockSubmitter<W: io::Write> {
+ writer: W,
+ pub waiting_on: usize,
}
-impl<'a, W: Write> RandomFasta<'a, W> {
- fn new(w: &'a mut W, a: &[AminoAcid]) -> RandomFasta<'a, W> {
- RandomFasta {
- seed: 42,
- out: w,
- lookup: make_lookup(a),
+impl<W: io::Write> BlockSubmitter<W> {
+ fn submit(&mut self, data: &[u8], block_num: usize) -> Option<io::Result<()>> {
+ if block_num == self.waiting_on {
+ self.waiting_on += 1;
+ Some(self.submit_async(data))
+ }
+ else {
+ None
}
}
- fn rng(&mut self, max: f32) -> f32 {
- self.seed = (self.seed * IA + IC) % IM;
- (max * self.seed as f32) / (IM as f32)
+ fn submit_async(&mut self, data: &[u8]) -> io::Result<()> {
+ self.writer.write_all(data)
}
+}
+
+
+// For repeating strings as output
+fn fasta_static<W: io::Write>(
+ writer: &mut W,
+ header: &[u8],
+ data: &[u8],
+ mut n: usize
+) -> io::Result<()>
+{
+ // The aim here is to print a short(ish) string cyclically
+ // with line breaks as appropriate.
+ //
+ // The secret technique is to repeat the string such that
+ // any wanted line is a single offset in the string.
+ //
+ // This technique is stolen from the Haskell version.
+
+ try!(writer.write_all(header));
- fn nextc(&mut self) -> u8 {
- let r = self.rng(LOOKUP_SCALE);
- for i in (r as usize..LOOKUP_SIZE) {
- if self.lookup[i].p >= r {
- return self.lookup[i].c;
+ // Maximum offset is data.len(),
+ // Maximum read len is LINE_LEN
+ let stream = data.iter().cloned().cycle();
+ let mut extended: Vec<u8> = stream.take(data.len() + LINE_LEN + 1).collect();
+
+ let mut offset = 0;
+ while n > 0 {
+ let write_len = min(LINE_LEN, n);
+ let end = offset + write_len;
+ n -= write_len;
+
+ let tmp = extended[end];
+ extended[end] = b'\n';
+ try!(writer.write_all(&extended[offset..end + 1]));
+ extended[end] = tmp;
+
+ offset = end;
+ offset %= data.len();
+ }
+
+ Ok(())
+}
+
+
+// For RNG streams as output
+fn fasta<W: io::Write + Send + 'static>(
+ submitter: &Arc<Mutex<BlockSubmitter<W>>>,
+ header: &[u8],
+ table: &'static [(u8, f32)],
+ rng: &mut Rng,
+ n: usize
+) -> io::Result<()>
+{
+ // Here the lookup table is part of the algorithm and needs the
+ // original probabilities (scaled with the LOOKUP_SCALE), because
+ // Isaac says so :-)
+ fn sum_and_scale(a: &'static [(u8, f32)]) -> Vec<(u8, f32)> {
+ let mut p = 0f32;
+ let mut result: Vec<(u8, f32)> = a.iter().map(|e| {
+ p += e.1;
+ (e.0, p * LOOKUP_SCALE)
+ }).collect();
+ let result_len = result.len();
+ result[result_len - 1].1 = LOOKUP_SCALE;
+ result
+ }
+
+ fn make_lookup(a: &[(u8, f32)]) -> [(u8, f32); LOOKUP_SIZE] {
+ let mut lookup = [(0, 0f32); LOOKUP_SIZE];
+ let mut j = 0;
+ for (i, slot) in lookup.iter_mut().enumerate() {
+ while a[j].1 < (i as f32) {
+ j += 1;
}
+ *slot = a[j];
}
- unreachable!();
+ lookup
+ }
+
+ {
+ try!(submitter.lock().unwrap().submit_async(header));
+ }
+
+ let lookup_table = Arc::new(make_lookup(&sum_and_scale(table)));
+
+ let thread_count = 4;
+ let mut threads = Vec::new();
+ for block_num in (0..thread_count) {
+ let offset = BLOCK_THOROUGHPUT * block_num;
+
+ let local_submitter = submitter.clone();
+ let local_lookup_table = lookup_table.clone();
+ let local_rng = rng.future(offset as u32);
+
+ threads.push(thread::spawn(move || {
+ gen_block(
+ local_submitter,
+ local_lookup_table,
+ local_rng,
+ n.saturating_sub(offset),
+ block_num,
+ thread_count
+ )
+ }));
+ }
+
+ for thread in threads {
+ try!(thread.join().unwrap());
}
- fn make(&mut self, n: usize) -> io::Result<()> {
- let lines = n / LINE_LEN;
- let chars_left = n % LINE_LEN;
- let mut buf = [0;LINE_LEN + 1];
+ *rng = rng.future(n as u32);
- for _ in 0..lines {
- for i in 0..LINE_LEN {
- buf[i] = self.nextc();
+ Ok(())
+}
+
+// A very optimized writer.
+// I have a feeling a simpler version wouldn't slow
+// things down too much, though, since the RNG
+// is the really heavy hitter.
+fn gen_block<W: io::Write>(
+ submitter: Arc<Mutex<BlockSubmitter<W>>>,
+ lookup_table: Arc<[(u8, f32)]>,
+ mut rng: Rng,
+ mut length: usize,
+ mut block_num: usize,
+ block_stride: usize,
+) -> io::Result<()>
+{
+ // Include newlines in block
+ length += length / LINE_LEN;
+ let block: &mut [u8] = &mut [b'\n'; BLOCK_LEN];
+
+ while length > 0 {
+ {
+ let gen_into = &mut block[..min(length, BLOCK_LEN)];
+
+ // Write random numbers, skipping newlines
+ for (i, byte) in gen_into.iter_mut().enumerate() {
+ if (i + 1) % (LINE_LEN + 1) != 0 {
+ let p = rng.gen() as f32 * (LOOKUP_SCALE / MODULUS as f32);
+ *byte = lookup_table[p as usize..LOOKUP_SIZE].iter().find(
+ |le| le.1 >= p).unwrap().0;
+ }
}
- buf[LINE_LEN] = '\n' as u8;
- try!(self.out.write(&buf));
}
- for i in 0..chars_left {
- buf[i] = self.nextc();
+
+ let write_out = {
+ if length >= BLOCK_LEN { &mut *block }
+ else if length % (LINE_LEN + 1) == 0 { &mut block[..length] }
+ else { &mut block[..length + 1] }
+ };
+
+ *write_out.last_mut().unwrap() = b'\n';
+ loop {
+ // Make sure to release lock before calling `yield_now`
+ let res = { submitter.lock().unwrap().submit(write_out, block_num) };
+
+ match res {
+ Some(result) => { try!(result); break; }
+ None => std::thread::yield_now()
+ }
}
- self.out.write_all(&buf[..chars_left])
+ block_num += block_stride;
+ rng = rng.future((BLOCK_THOROUGHPUT * (block_stride - 1)) as u32);
+ length = length.saturating_sub(BLOCK_LEN * (block_stride - 1));
+
+ length = length.saturating_sub(BLOCK_LEN);
}
+
+ Ok(())
}
-fn main() {
- let mut args = env::args();
- let n = if args.len() > 1 {
- args.nth(1).unwrap().parse::<usize>().unwrap()
- } else {
- 5
- };
+fn run<W: io::Write + Send + 'static>(writer: W) -> io::Result<()> {
+ let n = std::env::args_os().nth(1)
+ .and_then(|s| s.into_string().ok())
+ .and_then(|n| n.parse().ok())
+ .unwrap_or(1000);
- let stdout = io::stdout();
- let mut out = stdout.lock();
+ let rng = &mut Rng::new();
- out.write_all(b">ONE Homo sapiens alu\n").unwrap();
- {
- let mut repeat = RepeatFasta::new(ALU, &mut out);
- repeat.make(n * 2).unwrap();
- }
+ // Use automatic buffering for the static version...
+ let mut writer = io::BufWriter::with_capacity(STDIN_BUF, writer);
+ try!(fasta_static(&mut writer, b">ONE Homo sapiens alu\n", ALU, n * 2));
+
+ // ...but the dynamic version does its own buffering already
+ let writer = try!(writer.into_inner());
+ let submitter = Arc::new(Mutex::new(BlockSubmitter { writer: writer, waiting_on: 0 }));
- out.write_all(b">TWO IUB ambiguity codes\n").unwrap();
- let iub = sum_and_scale(&IUB);
- let mut random = RandomFasta::new(&mut out, &iub);
- random.make(n * 3).unwrap();
+ { submitter.lock().unwrap().waiting_on = 0; }
+ try!(fasta(&submitter, b">TWO IUB ambiguity codes\n", &IUB, rng, n * 3));
+ { submitter.lock().unwrap().waiting_on = 0; }
+ try!(fasta(&submitter, b">THREE Homo sapiens frequency\n", &HOMOSAPIENS, rng, n * 5));
- random.out.write_all(b">THREE Homo sapiens frequency\n").unwrap();
- let homo_sapiens = sum_and_scale(&HOMO_SAPIENS);
- random.lookup = make_lookup(&homo_sapiens);
- random.make(n * 5).unwrap();
+ Ok(())
+}
- random.out.write_all(b"\n").unwrap();
+fn main() {
+ run(io::stdout()).unwrap()
}
// OF THE POSSIBILITY OF SUCH DAMAGE.
use std::cmp::min;
-use std::env;
-use std::fs::File;
-use std::io::{self, BufWriter};
-use std::io::prelude::*;
+use std::io::{self, Write};
+use std::sync::{Arc, Mutex};
+use std::thread;
-const LINE_LENGTH: usize = 60;
-const IM: u32 = 139968;
-struct MyRandom {
+const LINE_LEN: usize = 60;
+
+const BLOCK_LINES: usize = 512;
+const BLOCK_THOROUGHPUT: usize = LINE_LEN * BLOCK_LINES;
+const BLOCK_LEN: usize = BLOCK_THOROUGHPUT + BLOCK_LINES;
+
+const STDIN_BUF: usize = (LINE_LEN + 1) * 1024;
+
+
+const ALU: &'static [u8] =
+ b"GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\
+ GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\
+ CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\
+ ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\
+ GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\
+ AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\
+ AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
+
+const IUB: &'static [(u8, f32)] =
+ &[(b'a', 0.27), (b'c', 0.12), (b'g', 0.12),
+ (b't', 0.27), (b'B', 0.02), (b'D', 0.02),
+ (b'H', 0.02), (b'K', 0.02), (b'M', 0.02),
+ (b'N', 0.02), (b'R', 0.02), (b'S', 0.02),
+ (b'V', 0.02), (b'W', 0.02), (b'Y', 0.02)];
+
+const HOMOSAPIENS: &'static [(u8, f32)] =
+ &[(b'a', 0.3029549426680),
+ (b'c', 0.1979883004921),
+ (b'g', 0.1975473066391),
+ (b't', 0.3015094502008)];
+
+
+// We need a specific Rng,
+// so implement this manually
+const MODULUS: u32 = 139968;
+const MULTIPLIER: u32 = 3877;
+const ADDITIVE: u32 = 29573;
+
+// Why doesn't rust already have this?
+// Algorithm directly taken from Wikipedia
+fn powmod(mut base: u64, mut exponent: u32, modulus: u64) -> u64 {
+ let mut ret = 1;
+ base %= modulus;
+
+ while exponent > 0 {
+ if exponent & 1 == 1 {
+ ret *= base;
+ ret %= modulus;
+ }
+ exponent >>= 1;
+ base *= base;
+ base %= modulus;
+ }
+
+ ret
+}
+
+// Just a typical LCRNG
+pub struct Rng {
last: u32
}
-impl MyRandom {
- fn new() -> MyRandom { MyRandom { last: 42 } }
- fn normalize(p: f32) -> u32 {(p * IM as f32).floor() as u32}
- fn gen(&mut self) -> u32 {
- self.last = (self.last * 3877 + 29573) % IM;
+
+impl Rng {
+ pub fn new() -> Rng {
+ Rng { last: 42 }
+ }
+
+ pub fn max_value() -> u32 {
+ MODULUS - 1
+ }
+
+ pub fn normalize(p: f32) -> u32 {
+ (p * MODULUS as f32).floor() as u32
+ }
+
+ pub fn gen(&mut self) -> u32 {
+ self.last = (self.last * MULTIPLIER + ADDITIVE) % MODULUS;
self.last
}
+
+ // This allows us to fast-forward the RNG,
+ // allowing us to run it in parallel.
+ pub fn future(&self, n: u32) -> Rng {
+ let a = MULTIPLIER as u64;
+ let b = ADDITIVE as u64;
+ let m = MODULUS as u64;
+
+ // (a^n - 1) mod (a-1) m
+ // x_k = ((a^n x_0 mod m) + --------------------- b) mod m
+ // a - 1
+ //
+ // Since (a - 1) divides (a^n - 1) mod (a-1) m,
+ // the subtraction does not overflow and thus can be non-modular.
+ //
+ let new_seed =
+ (powmod(a, n, m) * self.last as u64) % m +
+ (powmod(a, n, (a-1) * m) - 1) / (a-1) * b;
+
+ Rng { last: (new_seed % m) as u32 }
+ }
}
-struct AAGen<'a> {
- rng: &'a mut MyRandom,
- data: Vec<(u32, u8)>
+
+// This will end up keeping track of threads, like
+// in the other multithreaded Rust version, in
+// order to keep writes in order.
+//
+// This is stolen from another multithreaded Rust
+// implementation, although that implementation
+// was not able to parallelize the RNG itself.
+struct BlockSubmitter<W: io::Write> {
+ writer: W,
+ pub waiting_on: usize,
}
-impl<'a> AAGen<'a> {
- fn new<'b>(rng: &'b mut MyRandom, aa: &[(char, f32)]) -> AAGen<'b> {
- let mut cum = 0.;
- let data = aa.iter()
- .map(|&(ch, p)| { cum += p; (MyRandom::normalize(cum), ch as u8) })
- .collect();
- AAGen { rng: rng, data: data }
+
+impl<W: io::Write> BlockSubmitter<W> {
+ fn submit(&mut self, data: &[u8], block_num: usize) -> Option<io::Result<()>> {
+ if block_num == self.waiting_on {
+ self.waiting_on += 1;
+ Some(self.submit_async(data))
+ }
+ else {
+ None
+ }
}
-}
-impl<'a> Iterator for AAGen<'a> {
- type Item = u8;
-
- fn next(&mut self) -> Option<u8> {
- let r = self.rng.gen();
- self.data.iter()
- .skip_while(|pc| pc.0 < r)
- .map(|&(_, c)| c)
- .next()
+
+ fn submit_async(&mut self, data: &[u8]) -> io::Result<()> {
+ self.writer.write_all(data)
}
}
-fn make_fasta<W: Write, I: Iterator<Item=u8>>(
- wr: &mut W, header: &str, mut it: I, mut n: usize)
- -> io::Result<()>
+
+// For repeating strings as output
+fn fasta_static<W: io::Write>(
+ writer: &mut W,
+ header: &[u8],
+ data: &[u8],
+ mut n: usize
+) -> io::Result<()>
{
- try!(wr.write(header.as_bytes()));
- let mut line = [0; LINE_LENGTH + 1];
+ // The aim here is to print a short(ish) string cyclically
+ // with line breaks as appropriate.
+ //
+ // The secret technique is to repeat the string such that
+ // any wanted line is a single offset in the string.
+ //
+ // This technique is stolen from the Haskell version.
+
+ try!(writer.write_all(header));
+
+ // Maximum offset is data.len(),
+ // Maximum read len is LINE_LEN
+ let stream = data.iter().cloned().cycle();
+ let mut extended: Vec<u8> = stream.take(data.len() + LINE_LEN + 1).collect();
+
+ let mut offset = 0;
while n > 0 {
- let nb = min(LINE_LENGTH, n);
- for i in 0..nb {
- line[i] = it.next().unwrap();
+ let write_len = min(LINE_LEN, n);
+ let end = offset + write_len;
+ n -= write_len;
+
+ let tmp = extended[end];
+ extended[end] = b'\n';
+ try!(writer.write_all(&extended[offset..end + 1]));
+ extended[end] = tmp;
+
+ offset = end;
+ offset %= data.len();
+ }
+
+ Ok(())
+}
+
+
+// For RNG streams as output
+fn fasta<W: io::Write + Send + 'static>(
+ submitter: &Arc<Mutex<BlockSubmitter<W>>>,
+ header: &[u8],
+ table: &[(u8, f32)],
+ rng: &mut Rng,
+ n: usize
+) -> io::Result<()>
+{
+ // There's another secret technique in use here:
+ // we generate a lookup table to cache search of the
+ // aa buffer.
+ //
+ // The secret technique used is stolen from Haskell's
+ // implementation, and is the main secret to the Haskell
+ // implementation's speed.
+ fn gen_lookup_table(aa: &[(u8, f32)]) -> Vec<u8> {
+ let mut table = Vec::with_capacity(Rng::max_value() as usize + 1);
+
+ let mut cumulative_prob = 0.0;
+ let mut cumulative_norm = 0;
+
+ for &(byte, prob) in aa {
+ let last_norm = cumulative_norm;
+ cumulative_prob += prob;
+ cumulative_norm = min(Rng::max_value(), Rng::normalize(cumulative_prob)) + 1;
+
+ table.extend((0..cumulative_norm - last_norm).map(|_| byte));
}
- n -= nb;
- line[nb] = '\n' as u8;
- try!(wr.write(&line[..nb+1]));
+
+ table
+ }
+
+ {
+ try!(submitter.lock().unwrap().submit_async(header));
}
+
+ let lookup_table = Arc::new(gen_lookup_table(table));
+
+ let thread_count = 4; // avoid external dependency
+ let mut threads = Vec::new();
+ for block_num in (0..thread_count) {
+ let offset = BLOCK_THOROUGHPUT * block_num;
+
+ let local_submitter = submitter.clone();
+ let local_lookup_table = lookup_table.clone();
+ let local_rng = rng.future(offset as u32);
+
+ threads.push(thread::spawn(move || {
+ gen_block(
+ local_submitter,
+ local_lookup_table,
+ local_rng,
+ n.saturating_sub(offset),
+ block_num,
+ thread_count
+ )
+ }));
+ }
+
+ for thread in threads {
+ try!(thread.join().unwrap());
+ }
+
+ *rng = rng.future(n as u32);
+
Ok(())
}
-fn run<W: Write>(writer: &mut W) -> io::Result<()> {
- let mut args = env::args();
- let n = if env::var_os("RUST_BENCH").is_some() {
- 25000000
- } else if args.len() <= 1 {
- 1000
- } else {
- args.nth(1).unwrap().parse().unwrap()
- };
-
- let rng = &mut MyRandom::new();
- let alu =
- "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG\
- GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA\
- CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT\
- ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA\
- GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG\
- AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC\
- AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
- let iub = &[('a', 0.27), ('c', 0.12), ('g', 0.12),
- ('t', 0.27), ('B', 0.02), ('D', 0.02),
- ('H', 0.02), ('K', 0.02), ('M', 0.02),
- ('N', 0.02), ('R', 0.02), ('S', 0.02),
- ('V', 0.02), ('W', 0.02), ('Y', 0.02)];
- let homosapiens = &[('a', 0.3029549426680),
- ('c', 0.1979883004921),
- ('g', 0.1975473066391),
- ('t', 0.3015094502008)];
-
- try!(make_fasta(writer, ">ONE Homo sapiens alu\n",
- alu.as_bytes().iter().cycle().cloned(), n * 2));
- try!(make_fasta(writer, ">TWO IUB ambiguity codes\n",
- AAGen::new(rng, iub), n * 3));
- try!(make_fasta(writer, ">THREE Homo sapiens frequency\n",
- AAGen::new(rng, homosapiens), n * 5));
-
- writer.flush()
+// A very optimized writer.
+// I have a feeling a simpler version wouldn't slow
+// things down too much, though, since the RNG
+// is the really heavy hitter.
+fn gen_block<W: io::Write>(
+ submitter: Arc<Mutex<BlockSubmitter<W>>>,
+ lookup_table: Arc<Vec<u8>>,
+ mut rng: Rng,
+ mut length: usize,
+ mut block_num: usize,
+ block_stride: usize,
+) -> io::Result<()>
+{
+ // Include newlines in block
+ length += length / LINE_LEN;
+ let block: &mut [u8] = &mut [b'\n'; BLOCK_LEN];
+
+ while length > 0 {
+ {
+ let gen_into = &mut block[..min(length, BLOCK_LEN)];
+
+ // Write random numbers, skipping newlines
+ for (i, byte) in gen_into.iter_mut().enumerate() {
+ if (i + 1) % (LINE_LEN + 1) != 0 {
+ *byte = lookup_table[rng.gen() as usize];
+ }
+ }
+ }
+
+ let write_out = {
+ if length >= BLOCK_LEN { &mut *block }
+ else if length % (LINE_LEN + 1) == 0 { &mut block[..length] }
+ else { &mut block[..length + 1] }
+ };
+
+ *write_out.last_mut().unwrap() = b'\n';
+ loop {
+ match submitter.lock().unwrap().submit(write_out, block_num) {
+ Some(result) => { try!(result); break; }
+ None => std::thread::yield_now()
+ }
+ }
+ block_num += block_stride;
+ rng = rng.future((BLOCK_THOROUGHPUT * (block_stride - 1)) as u32);
+ length = length.saturating_sub(BLOCK_LEN * (block_stride - 1));
+
+ length = length.saturating_sub(BLOCK_LEN);
+ }
+
+ Ok(())
}
+
+fn run<W: io::Write + Send + 'static>(writer: W) -> io::Result<()> {
+ let n = std::env::args_os().nth(1)
+ .and_then(|s| s.into_string().ok())
+ .and_then(|n| n.parse().ok())
+ .unwrap_or(1000);
+
+ let rng = &mut Rng::new();
+
+ // Use automatic buffering for the static version...
+ let mut writer = io::BufWriter::with_capacity(STDIN_BUF, writer);
+ try!(fasta_static(&mut writer, b">ONE Homo sapiens alu\n", ALU, n * 2));
+
+ // ...but the dynamic version does its own buffering already
+ let writer = try!(writer.into_inner());
+ let submitter = Arc::new(Mutex::new(BlockSubmitter { writer: writer, waiting_on: 0 }));
+
+ { submitter.lock().unwrap().waiting_on = 0; }
+ try!(fasta(&submitter, b">TWO IUB ambiguity codes\n", &IUB, rng, n * 3));
+ { submitter.lock().unwrap().waiting_on = 0; }
+ try!(fasta(&submitter, b">THREE Homo sapiens frequency\n", &HOMOSAPIENS, rng, n * 5));
+
+ Ok(())
+}
+
+
fn main() {
- let res = if env::var_os("RUST_BENCH").is_some() {
- let mut file = BufWriter::new(File::create("./shootout-fasta.data").unwrap());
- run(&mut file)
- } else {
- run(&mut io::stdout())
- };
- res.unwrap()
+ run(io::stdout()).unwrap()
}
i += 2;
}
- res.push(cur_byte^-1);
+ res.push(cur_byte^!0);
}
}
// OF THE POSSIBILITY OF SUCH DAMAGE.
use std::mem;
+use std::ops::{Add, Sub, Mul};
const PI: f64 = 3.141592653589793;
const SOLAR_MASS: f64 = 4.0 * PI * PI;
const YEAR: f64 = 365.24;
const N_BODIES: usize = 5;
+const N_PAIRS: usize = N_BODIES * (N_BODIES - 1) / 2;
-static BODIES: [Planet;N_BODIES] = [
+const BODIES: [Planet; N_BODIES] = [
// Sun
Planet {
- x: 0.0, y: 0.0, z: 0.0,
- vx: 0.0, vy: 0.0, vz: 0.0,
+ pos: Vec3(0.0, 0.0, 0.0),
+ vel: Vec3(0.0, 0.0, 0.0),
mass: SOLAR_MASS,
},
// Jupiter
Planet {
- x: 4.84143144246472090e+00,
- y: -1.16032004402742839e+00,
- z: -1.03622044471123109e-01,
- vx: 1.66007664274403694e-03 * YEAR,
- vy: 7.69901118419740425e-03 * YEAR,
- vz: -6.90460016972063023e-05 * YEAR,
+ pos: Vec3(4.84143144246472090e+00,
+ -1.16032004402742839e+00,
+ -1.03622044471123109e-01),
+ vel: Vec3(1.66007664274403694e-03 * YEAR,
+ 7.69901118419740425e-03 * YEAR,
+ -6.90460016972063023e-05 * YEAR),
mass: 9.54791938424326609e-04 * SOLAR_MASS,
},
// Saturn
Planet {
- x: 8.34336671824457987e+00,
- y: 4.12479856412430479e+00,
- z: -4.03523417114321381e-01,
- vx: -2.76742510726862411e-03 * YEAR,
- vy: 4.99852801234917238e-03 * YEAR,
- vz: 2.30417297573763929e-05 * YEAR,
+ pos: Vec3(8.34336671824457987e+00,
+ 4.12479856412430479e+00,
+ -4.03523417114321381e-01),
+ vel: Vec3(-2.76742510726862411e-03 * YEAR,
+ 4.99852801234917238e-03 * YEAR,
+ 2.30417297573763929e-05 * YEAR),
mass: 2.85885980666130812e-04 * SOLAR_MASS,
},
// Uranus
Planet {
- x: 1.28943695621391310e+01,
- y: -1.51111514016986312e+01,
- z: -2.23307578892655734e-01,
- vx: 2.96460137564761618e-03 * YEAR,
- vy: 2.37847173959480950e-03 * YEAR,
- vz: -2.96589568540237556e-05 * YEAR,
+ pos: Vec3(1.28943695621391310e+01,
+ -1.51111514016986312e+01,
+ -2.23307578892655734e-01),
+ vel: Vec3(2.96460137564761618e-03 * YEAR,
+ 2.37847173959480950e-03 * YEAR,
+ -2.96589568540237556e-05 * YEAR),
mass: 4.36624404335156298e-05 * SOLAR_MASS,
},
// Neptune
Planet {
- x: 1.53796971148509165e+01,
- y: -2.59193146099879641e+01,
- z: 1.79258772950371181e-01,
- vx: 2.68067772490389322e-03 * YEAR,
- vy: 1.62824170038242295e-03 * YEAR,
- vz: -9.51592254519715870e-05 * YEAR,
+ pos: Vec3(1.53796971148509165e+01,
+ -2.59193146099879641e+01,
+ 1.79258772950371181e-01),
+ vel: Vec3(2.68067772490389322e-03 * YEAR,
+ 1.62824170038242295e-03 * YEAR,
+ -9.51592254519715870e-05 * YEAR),
mass: 5.15138902046611451e-05 * SOLAR_MASS,
},
];
-#[derive(Copy, Clone)]
+/// A 3d Vector type with oveloaded operators to improve readability.
+#[derive(Clone, Copy)]
+struct Vec3(pub f64, pub f64, pub f64);
+
+impl Vec3 {
+ fn zero() -> Self { Vec3(0.0, 0.0, 0.0) }
+
+ fn norm(&self) -> f64 { self.squared_norm().sqrt() }
+
+ fn squared_norm(&self) -> f64 {
+ self.0 * self.0 + self.1 * self.1 + self.2 * self.2
+ }
+}
+
+impl Add for Vec3 {
+ type Output = Self;
+ fn add(self, rhs: Self) -> Self {
+ Vec3(self.0 + rhs.0, self.1 + rhs.1, self.2 + rhs.2)
+ }
+}
+
+impl Sub for Vec3 {
+ type Output = Self;
+ fn sub(self, rhs: Self) -> Self {
+ Vec3(self.0 - rhs.0, self.1 - rhs.1, self.2 - rhs.2)
+ }
+}
+
+impl Mul<f64> for Vec3 {
+ type Output = Self;
+ fn mul(self, rhs: f64) -> Self {
+ Vec3(self.0 * rhs, self.1 * rhs, self.2 * rhs)
+ }
+}
+
+#[derive(Clone, Copy)]
struct Planet {
- x: f64, y: f64, z: f64,
- vx: f64, vy: f64, vz: f64,
+ pos: Vec3,
+ vel: Vec3,
mass: f64,
}
-fn advance(bodies: &mut [Planet;N_BODIES], dt: f64, steps: isize) {
- for _ in 0..steps {
- let mut b_slice: &mut [_] = bodies;
- loop {
- let bi = match shift_mut_ref(&mut b_slice) {
- Some(bi) => bi,
- None => break
- };
- for bj in &mut *b_slice {
- let dx = bi.x - bj.x;
- let dy = bi.y - bj.y;
- let dz = bi.z - bj.z;
-
- let d2 = dx * dx + dy * dy + dz * dz;
- let mag = dt / (d2 * d2.sqrt());
-
- let massj_mag = bj.mass * mag;
- bi.vx -= dx * massj_mag;
- bi.vy -= dy * massj_mag;
- bi.vz -= dz * massj_mag;
-
- let massi_mag = bi.mass * mag;
- bj.vx += dx * massi_mag;
- bj.vy += dy * massi_mag;
- bj.vz += dz * massi_mag;
- }
- bi.x += dt * bi.vx;
- bi.y += dt * bi.vy;
- bi.z += dt * bi.vz;
+/// Computes all pairwise position differences between the planets.
+fn pairwise_diffs(bodies: &[Planet; N_BODIES], diff: &mut [Vec3; N_PAIRS]) {
+ let mut bodies = bodies.iter();
+ let mut diff = diff.iter_mut();
+ while let Some(bi) = bodies.next() {
+ for bj in bodies.clone() {
+ *diff.next().unwrap() = bi.pos - bj.pos;
+ }
+ }
+}
+
+/// Computes the magnitude of the force between each pair of planets.
+fn magnitudes(diff: &[Vec3; N_PAIRS], dt: f64, mag: &mut [f64; N_PAIRS]) {
+ for (mag, diff) in mag.iter_mut().zip(diff.iter()) {
+ let d2 = diff.squared_norm();
+ *mag = dt / (d2 * d2.sqrt());
+ }
+}
+
+/// Updates the velocities of the planets by computing their gravitational
+/// accelerations and performing one step of Euler integration.
+fn update_velocities(bodies: &mut [Planet; N_BODIES], dt: f64,
+ diff: &mut [Vec3; N_PAIRS], mag: &mut [f64; N_PAIRS]) {
+ pairwise_diffs(bodies, diff);
+ magnitudes(&diff, dt, mag);
+
+ let mut bodies = &mut bodies[..];
+ let mut mag = mag.iter();
+ let mut diff = diff.iter();
+ while let Some(bi) = shift_mut_ref(&mut bodies) {
+ for bj in bodies.iter_mut() {
+ let diff = *diff.next().unwrap();
+ let mag = *mag.next().unwrap();
+ bi.vel = bi.vel - diff * (bj.mass * mag);
+ bj.vel = bj.vel + diff * (bi.mass * mag);
}
}
}
-fn energy(bodies: &[Planet;N_BODIES]) -> f64 {
+/// Advances the solar system by one timestep by first updating the
+/// velocities and then integrating the positions using the updated velocities.
+///
+/// Note: the `diff` & `mag` arrays are effectively scratch space. They're
+/// provided as arguments to avoid re-zeroing them every time `advance` is
+/// called.
+fn advance(mut bodies: &mut [Planet; N_BODIES], dt: f64,
+ diff: &mut [Vec3; N_PAIRS], mag: &mut [f64; N_PAIRS]) {
+ update_velocities(bodies, dt, diff, mag);
+ for body in bodies.iter_mut() {
+ body.pos = body.pos + body.vel * dt;
+ }
+}
+
+/// Computes the total energy of the solar system.
+fn energy(bodies: &[Planet; N_BODIES]) -> f64 {
let mut e = 0.0;
let mut bodies = bodies.iter();
- loop {
- let bi = match bodies.next() {
- Some(bi) => bi,
- None => break
- };
- e += (bi.vx * bi.vx + bi.vy * bi.vy + bi.vz * bi.vz) * bi.mass / 2.0;
- for bj in bodies.clone() {
- let dx = bi.x - bj.x;
- let dy = bi.y - bj.y;
- let dz = bi.z - bj.z;
- let dist = (dx * dx + dy * dy + dz * dz).sqrt();
- e -= bi.mass * bj.mass / dist;
- }
+ while let Some(bi) = bodies.next() {
+ e += bi.vel.squared_norm() * bi.mass / 2.0
+ - bi.mass * bodies.clone()
+ .map(|bj| bj.mass / (bi.pos - bj.pos).norm())
+ .fold(0.0, |a, b| a + b);
}
e
}
-fn offset_momentum(bodies: &mut [Planet;N_BODIES]) {
- let mut px = 0.0;
- let mut py = 0.0;
- let mut pz = 0.0;
- for bi in bodies.iter() {
- px += bi.vx * bi.mass;
- py += bi.vy * bi.mass;
- pz += bi.vz * bi.mass;
- }
- let sun = &mut bodies[0];
- sun.vx = - px / SOLAR_MASS;
- sun.vy = - py / SOLAR_MASS;
- sun.vz = - pz / SOLAR_MASS;
+/// Offsets the sun's velocity to make the overall momentum of the system zero.
+fn offset_momentum(bodies: &mut [Planet; N_BODIES]) {
+ let p = bodies.iter().fold(Vec3::zero(), |v, b| v + b.vel * b.mass);
+ bodies[0].vel = p * (-1.0 / bodies[0].mass);
}
fn main() {
.unwrap_or(1000)
};
let mut bodies = BODIES;
+ let mut diff = [Vec3::zero(); N_PAIRS];
+ let mut mag = [0.0f64; N_PAIRS];
offset_momentum(&mut bodies);
println!("{:.9}", energy(&bodies));
- advance(&mut bodies, 0.01, n);
+ for _ in 0..n {
+ advance(&mut bodies, 0.01, &mut diff, &mut mag);
+ }
println!("{:.9}", energy(&bodies));
}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use std::mem;
-
-fn leak<T>(mut b: Box<T>) -> &'static mut T {
- // isn't this supposed to be safe?
- let inner = &mut *b as *mut _;
- mem::forget(b);
- unsafe { &mut *inner }
-}
-
-fn evil(mut s: &'static mut String)
-{
- // create alias
- let alias: &'static mut String = s;
- let inner: &str = &alias;
- // free value
- *s = String::new(); //~ ERROR cannot assign
- let _spray = "0wned".to_owned();
- // ... and then use it
- println!("{}", inner);
-}
-
-fn main() {
- evil(leak(Box::new("hello".to_owned())));
-}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]])
+#[no_mangle]
+fn helper(_: usize) {
+}
+
+// CHECK-LABEL: @no_op_slice_adjustment
+#[no_mangle]
+pub fn no_op_slice_adjustment(x: &[u8]) -> &[u8] {
+ // We used to generate an extra alloca and memcpy for the block's trailing expression value, so
+ // check that we copy directly to the return value slot
+// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to
+// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %sret_slot to i8*
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]],
+ { x }
+}
+
+// CHECK-LABEL: @no_op_slice_adjustment2
+#[no_mangle]
+pub fn no_op_slice_adjustment2(x: &[u8]) -> &[u8] {
+ // We used to generate an extra alloca and memcpy for the function's return value, so check
+ // that there's no memcpy (the slice is written to sret_slot element-wise)
+// CHECK-NOT: call void @llvm.memcpy.
+ no_op_slice_adjustment(x)
+}
// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+
static X: i32 = 5;
// CHECK-LABEL: @raw_ptr_to_raw_ptr_noop
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// Below, these constants are defined as enum variants that by itself would
+// have a lower alignment than the enum type. Ensure that we mark them
+// correctly with the higher alignment of the enum.
+
+// CHECK: @STATIC = {{.*}}, align 4
+
+// This checks the constants from inline_enum_const
+// CHECK: @const{{[0-9]+}} = {{.*}}, align 2
+
+// This checks the constants from {low,high}_align_const, they share the same
+// constant, but the alignment differs, so the higher one should be used
+// CHECK: @const{{[0-9]+}} = {{.*}}, align 4
+
+#[derive(Copy, Clone)]
+
+// repr(i16) is required for the {low,high}_align_const test
+#[repr(i16)]
+pub enum E<A, B> {
+ A(A),
+ B(B),
+}
+
+#[no_mangle]
+pub static STATIC: E<i16, i32> = E::A(0);
+
+// CHECK-LABEL: @static_enum_const
+#[no_mangle]
+pub fn static_enum_const() -> E<i16, i32> {
+ STATIC
+}
+
+// CHECK-LABEL: @inline_enum_const
+#[no_mangle]
+pub fn inline_enum_const() -> E<i8, i16> {
+ E::A(0)
+}
+
+// CHECK-LABEL: @low_align_const
+#[no_mangle]
+pub fn low_align_const() -> E<i16, [i16; 3]> {
+// Check that low_align_const and high_align_const use the same constant
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]+}}, i8* {{.*}} [[LOW_HIGH:@const[0-9]+]]
+ E::A(0)
+}
+
+// CHECK-LABEL: @high_align_const
+#[no_mangle]
+pub fn high_align_const() -> E<i16, i32> {
+// Check that low_align_const and high_align_const use the same constant
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* %{{[0-9]}}, i8* {{.*}} [[LOW_HIGH]]
+ E::A(0)
+}
// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
#![feature(unwind_attributes)]
extern {
// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
#![feature(allocator)]
pub struct S {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// ignore-windows
+// ignore-macos
+
+// compile-flags: -g -C no-prepopulate-passes
+
+#![feature(start)]
+
+// CHECK-LABEL: @main
+// CHECK: load volatile i8, i8* getelementptr inbounds ([[B:\[[0-9]* x i8\]]], [[B]]* @__rustc_debug_gdb_scripts_section__, i32 0, i32 0), align 1
+
+#[start]
+fn start(_: isize, _: *const *const u8) -> isize {
+ return 0;
+}
// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+
// CHECK: @VAR1 = constant i32 1, section ".test_one"
#[no_mangle]
#[link_section = ".test_one"]
// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+
pub struct Bytes {
a: u8,
b: u8,
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+pub enum E {
+ A,
+ B,
+}
+
+// CHECK-LABEL: @exhaustive_match
+#[no_mangle]
+pub fn exhaustive_match(e: E) {
+// CHECK: switch{{.*}}, label %[[DEFAULT:[a-zA-Z0-9_]+]]
+// CHECK: [[DEFAULT]]:
+// CHECK-NEXT: unreachable
+ match e {
+ E::A => (),
+ E::B => (),
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+// Hack to get the correct size for the length part in slices
+// CHECK: @helper([[USIZE:i[0-9]+]])
+#[no_mangle]
+fn helper(_: usize) {
+}
+
+// CHECK-LABEL: @ref_dst
+#[no_mangle]
+pub fn ref_dst(s: &[u8]) {
+ // We used to generate an extra alloca and memcpy to ref the dst, so check that we copy
+ // directly to the alloca for "x"
+// CHECK: [[SRC:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %s to i8*
+// CHECK: [[DST:%[0-9]+]] = bitcast { i8*, [[USIZE]] }* %x to i8*
+// CHECK: call void @llvm.memcpy.{{.*}}(i8* [[DST]], i8* [[SRC]],
+ let x = &*s;
+}
// compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+
pub struct Bytes {
a: u8,
b: u8,
fn main() {
let mut a = Foo;
let ref b = Foo;
- a += *b; //~ Error: binary assignment operation `+=` cannot be applied to types `Foo` and `Foo`
+ a += *b; //~ Error: binary assignment operation `+=` cannot be applied to type `Foo`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Test that we report an error if the trait ref in an qualified type
+// Test that we report an error if the trait ref in a qualified type
// uses invalid type arguments.
trait Foo<T> {
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+#[inline]
+fn f() {}
+
+#[inline] //~ ERROR: attribute should be applied to function
+struct S;
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+#![feature(repr_simd)]
+
+#[repr(C)] //~ ERROR: attribute should be applied to struct or enum
+fn f() {}
+
+#[repr(C)]
+struct SExtern(f64, f64);
+
+#[repr(packed)]
+struct SPacked(f64, f64);
+
+#[repr(simd)]
+struct SSimd(f64, f64);
+
+#[repr(i8)] //~ ERROR: attribute should be applied to enum
+struct SInt(f64, f64);
+
+#[repr(C)]
+enum EExtern { A, B }
+
+#[repr(packed)] //~ ERROR: attribute should be applied to struct
+enum EPacked { A, B }
+
+#[repr(simd)] //~ ERROR: attribute should be applied to struct
+enum ESimd { A, B }
+
+#[repr(i8)]
+enum EInt { A, B }
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:augmented_assignments.rs
+
+// Test that the feature gate is needed when using augmented assignments that were overloaded in
+// another crate
+
+extern crate augmented_assignments;
+
+use augmented_assignments::Int;
+
+fn main() {
+ let mut x = Int(0);
+ x += 1;
+ //~^ error: overloaded augmented assignments are not stable
+ // | help: add #![feature(augmented_assignments)] to the crate root to enable
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::AddAssign;
+
+struct Int(i32);
+
+impl AddAssign<i32> for Int {
+ fn add_assign(&mut self, _: i32) {
+ unimplemented!()
+ }
+}
+
+fn main() {
+ let mut x = Int(0);
+ x += 1;
+ //~^ error: overloaded augmented assignments are not stable
+ // | help: add #![feature(augmented_assignments)] to the crate root to enable
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::AddAssign;
+//~^ error: use of unstable library feature 'op_assign_traits'
+
+struct Int(i32);
+
+impl AddAssign for Int {
+ //~^ error: use of unstable library feature 'op_assign_traits'
+ fn add_assign(&mut self, _: Int) {
+ //~^ error: use of unstable library feature 'op_assign_traits'
+ unimplemented!()
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(augmented_assignments)]
+
+use std::ops::AddAssign;
+
+struct Int(i32);
+
+impl AddAssign for Int {
+ fn add_assign(&mut self, _: Int) {
+ unimplemented!()
+ }
+}
+
+fn main() {
+ let mut x = Int(1);
+ x //~ error: use of moved value: `x`
+ +=
+ x; //~ note: `x` moved here because it has type `Int`, which is non-copyable
+
+ let y = Int(2);
+ y //~ error: cannot borrow immutable local variable `y` as mutable
+ +=
+ Int(1);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(unknown_features)]
#![feature(box_syntax)]
struct clam {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(unknown_features)]
#![feature(box_syntax)]
struct Foo(Box<isize>, isize);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Copy, Clone)]
+struct S;
+
+impl S {
+ fn mutate(&mut self) {
+ }
+}
+
+fn func(arg: S) {
+ arg.mutate(); //~ ERROR: cannot borrow immutable argument
+}
+
+impl S {
+ fn method(&self, arg: S) {
+ arg.mutate(); //~ ERROR: cannot borrow immutable argument
+ }
+}
+
+trait T {
+ fn default(&self, arg: S) {
+ arg.mutate(); //~ ERROR: cannot borrow immutable argument
+ }
+}
+
+impl T for S {}
+
+fn main() {
+ let s = S;
+ func(s);
+ s.method(s);
+ s.default(s);
+ (|arg: S| { arg.mutate() })(s); //~ ERROR: cannot borrow immutable argument
+}
x.y = 3; //~ ERROR cannot borrow
}
-// FIXME(eddyb) #12825 This shouldn't attempt to call deref_mut.
-/*
fn deref_imm_method(x: Own<Point>) {
let __isize = x.get();
}
-*/
fn deref_mut_method1(x: Own<Point>) {
x.set(0, 0); //~ ERROR cannot borrow
}
fn e(x: &mut isize) {
- let c1 = || x = panic!(); //~ ERROR closure cannot assign to immutable local variable
+ let c1 = || x = panic!(); //~ ERROR closure cannot assign to immutable argument
}
fn main() {
fn produce<T>() -> T { panic!(); }
fn inc(v: &mut Box<isize>) {
- *v = box() (**v + 1);
- //~^ WARN deprecated syntax
+ *v = box (**v + 1);
}
fn pre_freeze_cond() {
fn produce<T>() -> T { panic!(); }
fn inc(v: &mut Box<isize>) {
- *v = box() (**v + 1);
- //~^ WARN deprecated syntax
+ *v = box (**v + 1);
}
fn loop_overarching_alias_mut() {
fn produce<T>() -> T { panic!(); }
fn inc(v: &mut Box<isize>) {
- *v = box() (**v + 1);
- //~^ WARN deprecated syntax
+ *v = box (**v + 1);
}
fn pre_freeze() {
fn add(self, f: foo) -> foo {
let foo(box i) = self;
let foo(box j) = f;
- foo(box() (i + j))
- //~^ WARN deprecated syntax
+ foo(box (i + j))
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::mem;
+
+fn leak<T>(mut b: Box<T>) -> &'static mut T {
+ // isn't this supposed to be safe?
+ let inner = &mut *b as *mut _;
+ mem::forget(b);
+ unsafe { &mut *inner }
+}
+
+fn evil(mut s: &'static mut String)
+{
+ // create alias
+ let alias: &'static mut String = s;
+ let inner: &str = &alias;
+ // free value
+ *s = String::new(); //~ ERROR cannot assign
+ let _spray = "0wned".to_owned();
+ // ... and then use it
+ println!("{}", inner);
+}
+
+fn main() {
+ evil(leak(Box::new("hello".to_owned())));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test to ensure we only report an error for the first issued loan that
+// conflicts with a new loan, as opposed to every issued loan. This keeps us
+// down to O(n) errors (for n problem lines), instead of O(n^2) errors.
+
+fn main() {
+ let mut x = 1;
+ let mut addr;
+ loop {
+ match 1 {
+ 1 => { addr = &mut x; }
+ //~^ ERROR cannot borrow `x` as mutable more than once at a time
+ 2 => { addr = &mut x; }
+ //~^ ERROR cannot borrow `x` as mutable more than once at a time
+ _ => { addr = &mut x; }
+ //~^ ERROR cannot borrow `x` as mutable more than once at a time
+ }
+ }
+}
}
fn b<F:FnMut(isize, isize) -> isize>(f: F) {
- f(1, 2); //~ ERROR cannot borrow immutable local variable
+ f(1, 2); //~ ERROR cannot borrow immutable argument
}
fn c<F:FnOnce(isize, isize) -> isize>(f: F) {
// except according to those terms.
fn main() {
- let u = (5 as bool);
+ let u = 5 as bool;
//~^ ERROR cannot cast as `bool`
//~^^ HELP compare with zero instead
}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[allow(exceeding_bitshifts)]
+#[deny(const_err)]
+
+fn black_box<T>(_: T) {
+ unimplemented!()
+}
+
+const BLA: u8 = 200u8 + 200u8;
+//~^ ERROR attempted to add with overflow
+
+fn main() {
+ let a = -std::i8::MIN;
+ //~^ WARN attempted to negate with overflow
+ let b = 200u8 + 200u8 + 200u8;
+ //~^ WARN attempted to add with overflow
+ //~^^ WARN attempted to add with overflow
+ let c = 200u8 * 4;
+ //~^ WARN attempted to mul with overflow
+ let d = 42u8 - (42u8 + 1);
+ //~^ WARN attempted to sub with overflow
+ let _e = BLA;
+ black_box(a);
+ black_box(b);
+ black_box(c);
+ black_box(d);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(negate_unsigned)]
-
#![allow(unused_imports)]
#![feature(negate_unsigned)]
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that error in constant evaluation of enum discriminant
+// provides the context for what caused the evaluation.
+
+struct S(i32);
+
+const CONSTANT: S = S(0);
+//~^ ERROR: constant evaluation error: non-constant path in constant expression [E0080]
+
+enum E {
+ V = CONSTANT,
+ //~^ NOTE: for enum discriminant here
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// test that certain things are disallowed in const fn signatures
+
+#![feature(const_fn)]
+
+// no destructuring
+const fn i((a, b): (u32, u32)) -> u32 { a + b } //~ ERROR: E0022
+
+fn main() {}
use const_fn_lib::foo;
fn main() {
- let x: [usize; foo()] = []; //~ ERROR unsupported constant expr
+ let x: [usize; foo()] = []; //~ ERROR non-constant path in constant expr
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Check that an constant-evaluation underflow highlights the correct
+// Check that a constant-evaluation underflow highlights the correct
// spot (where the underflow occurred), while also providing the
// overall context for what caused the evaluation.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Check that an constant-evaluation underflow highlights the correct
+// Check that a constant-evaluation underflow highlights the correct
// spot (where the underflow occurred).
const ONE: usize = 1;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+const FOO: &'static[u32] = &[1, 2, 3];
+const BAR: u32 = FOO[5]; //~ ERROR const index-expr is out of bounds
+
+fn main() {
+ let _ = BAR;
+}
#[derive(FromPrimitive)]
enum C { Foo(isize), Bar(usize) }
-//~^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments
-//~^^^ ERROR `FromPrimitive` cannot be derived for enum variants with arguments
+//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
+//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
#[derive(FromPrimitive)]
enum D { Baz { x: isize } }
-//~^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants
-//~^^^ ERROR `FromPrimitive` cannot be derived for enums with struct variants
+//~^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
+//~^^^ ERROR `FromPrimitive` cannot be derived for enums with non-unit variants
pub fn main() {}
use id::Id;
mod s {
- #![allow(unstable)]
use std::sync::atomic::{AtomicUsize, Ordering};
static S_COUNT: AtomicUsize = AtomicUsize::new(0);
// which is a reduction of this code to more directly show the reason
// for the error message we see here.)
-#![allow(unstable)]
#![feature(const_fn)]
extern crate arena;
use id::Id;
mod s {
- #![allow(unstable)]
use std::sync::atomic::{AtomicUsize, Ordering};
static S_COUNT: AtomicUsize = AtomicUsize::new(0);
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Check that a arena (TypedArena) cannot carry elements whose drop
+// Check that an arena (TypedArena) cannot carry elements whose drop
// methods might access borrowed data of lifetime that does not
// strictly outlive the arena itself.
//
// (Also compare against dropck_tarena_cycle_checked.rs, from which
// this was reduced to better understand its error message.)
-#![allow(unstable)]
-
extern crate arena;
use arena::TypedArena;
// In the code below, the impl of HasId for `&'a usize` does not
// actually access the borrowed data, but the point is that the
// interface to CheckId does not (and cannot) know that, and therefore
-// when encountering the a value V of type CheckId<S>, we must
+// when encountering a value V of type CheckId<S>, we must
// conservatively force the type S to strictly outlive V.
impl<T:HasId> Drop for CheckId<T> {
fn drop(&mut self) {
// except according to those terms.
// Reject mixing cyclic structure and Drop when using trait
-// objects to hide the the cross-references.
+// objects to hide the cross-references.
//
// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
use id::Id;
mod s {
- #![allow(unstable)]
use std::sync::atomic::{AtomicUsize, Ordering};
static S_COUNT: AtomicUsize = AtomicUsize::new(0);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// error-pattern:already defined
+
+
+#![allow(warnings)]
+
+fn main() {
+ {
+ extern fn fail() {}
+ }
+ {
+ extern fn fail() {}
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// `/**/` was previously regarded as a doc comment because it starts with `/**` and ends with `*/`.
+// This could break some internal logic that assumes the length of a doc comment is at least 5,
+// leading to an ICE.
+
+fn main() {
+ println!(/**/); //~ ERROR unexpected end
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use empty braced struct as constant or constructor function
+
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+
+enum E {
+ Empty2 {}
+}
+
+fn main() {
+ let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant
+ let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant
+ let e2 = E::Empty2; //~ ERROR `E::Empty2` is the name of a struct or struct variant
+ let e2 = E::Empty2(); //~ ERROR `E::Empty2` is the name of a struct or struct variant
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Feature gate test for empty struct with braces
+// Can't define an empty braced struct
+
+struct Empty1 {} //~ ERROR empty structs and enum variants with braces are unstable
+struct Empty2;
+
+enum E {
+ Empty4 {}, //~ ERROR empty structs and enum variants with braces are unstable
+ Empty5,
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Feature gate test for empty struct with braces
+// Can't use braced expressions and patterns with structs defined without braces
+
+struct Empty2;
+
+enum E {
+ Empty5,
+}
+
+fn main() {
+ let e2: Empty2 = Empty2 {}; //~ ERROR empty structs and enum variants with braces are unstable
+ let e2: Empty2 = Empty2;
+ // Issue #28692
+ // let e5: E = E::Empty5 {}; // ERROR empty structs and enum variants with braces are unstable
+ let e5: E = E::Empty5;
+
+ match e2 {
+ Empty2 {} => {} //~ ERROR empty structs and enum variants with braces are unstable
+ }
+ match e2 {
+ Empty2 => {}
+ }
+ match e2 {
+ Empty2 { .. } => {} //~ ERROR empty structs and enum variants with braces are unstable
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 {} => {} // ERROR empty structs and enum variants with braces are unstable
+ // }
+ match e5 {
+ E::Empty5 => {}
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 { .. } => {} // ERROR empty structs and enum variants with braces are unstable
+ // }
+
+ let e22 = Empty2 { ..e2 }; //~ ERROR empty structs and enum variants with braces are unstable
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use empty braced struct as constant pattern
+
+#![deny(warnings)]
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+
+enum E {
+ Empty2 {}
+}
+
+fn main() {
+ let e1 = Empty1 {};
+ let e2 = E::Empty2 {};
+
+ // Issue #28692
+ // match e1 {
+ // Empty1 => () // ERROR incorrect error
+ // }
+ match e2 {
+ E::Empty2 => () //~ ERROR `E::Empty2` does not name a non-struct variant or a tuple struct
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use empty braced struct as enum pattern
+
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+
+enum E {
+ Empty2 {}
+}
+
+fn main() {
+ let e1 = Empty1 {};
+ let e2 = E::Empty2 {};
+
+ // Rejected by parser as yet
+ // match e1 {
+ // Empty1() => () // ERROR unresolved enum variant, struct or const `Empty1`
+ // }
+ match e1 {
+ Empty1(..) => () //~ ERROR unresolved enum variant, struct or const `Empty1`
+ }
+ // Issue #28692
+ // match e2 {
+ // E::Empty2() => () // ERROR unresolved enum variant, struct or const `Empty2`
+ // }
+ // match e2 {
+ // E::Empty2(..) => () // ERROR unresolved enum variant, struct or const `Empty2`
+ // }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use unit struct as constructor function
+
+#![feature(braced_empty_structs)]
+
+struct Empty1;
+
+enum E {
+ Empty2
+}
+
+fn main() {
+ let e1 = Empty1(); //~ ERROR expected function, found `Empty1`
+ let e2 = E::Empty2(); //~ ERROR expected function, found `E`
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Can't use unit struct as enum pattern
+
+#![feature(braced_empty_structs)]
+
+FIXME //~ ERROR expected item, found `FIXME`
+
+struct Empty1;
+
+enum E {
+ Empty2
+}
+
+fn main() {
+ let e1 = Empty1;
+ let e2 = E::Empty2;
+
+ // Issue #28692
+ // match e1 {
+ // Empty1() => () // ERROR variable `Empty1` should have a snake case name
+ // }
+ // match e1 {
+ // Empty1(..) => () // ERROR variable `Empty1` should have a snake case name
+ // }
+ // match e2 {
+ // E::Empty2() => () // ERROR variable `Empty2` should have a snake case name
+ // }
+ // match e2 {
+ // E::Empty2(..) => () // ERROR variable `Empty2` should have a snake case name
+ // }
+}
fn main() {
let x = box 'c'; //~ ERROR box expression syntax is experimental
println!("x: {}", x);
-
- let x = box () 'c'; //~ ERROR box expression syntax is experimental
- //~^ WARN deprecated syntax
- println!("x: {}", x);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[cfg(target_vendor = "x")] //~ ERROR `cfg(target_vendor)` is experimental
+#[cfg_attr(target_vendor = "x", x)] //~ ERROR `cfg(target_vendor)` is experimental
+struct Foo(u64, u64);
+
+#[cfg(not(any(all(target_vendor = "x"))))] //~ ERROR `cfg(target_vendor)` is experimental
+fn foo() {}
+
+fn main() {
+ cfg!(target_vendor = "x");
+ //~^ ERROR `cfg(target_vendor)` is experimental and subject to change
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Ensure that attempts to use the unsafe attribute are feature-gated.
+
+// Example adapted from RFC 1238 text (just left out the feature gate).
+
+// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
+// #example-of-the-unguarded-escape-hatch
+
+// #![feature(dropck_parametricity)]
+
+use std::cell::Cell;
+
+struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+
+struct Foo<T> { data: Vec<T> }
+
+impl<T> Drop for Foo<T> {
+ #[unsafe_destructor_blind_to_params] // This is the UGEH attribute
+ //~^ ERROR unsafe_destructor_blind_to_params has unstable semantics
+ fn drop(&mut self) { }
+}
+
+fn main() {
+ let mut foo = Foo { data: Vec::new() };
+ foo.data.push(Concrete(0, Cell::new(None)));
+ foo.data.push(Concrete(0, Cell::new(None)));
+
+ foo.data[0].1.set(Some(&foo.data[1]));
+ foo.data[1].1.set(Some(&foo.data[0]));
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that negating unsigned integers is gated by `negate_unsigned` feature
+// gate
+
+struct S;
+impl std::ops::Neg for S {
+ type Output = u32;
+ fn neg(self) -> u32 { 0 }
+}
+
+const _MAX: usize = -1;
+//~^ ERROR unary negation of unsigned integers may be removed in the future
+
+fn main() {
+ let a = -1;
+ //~^ ERROR unary negation of unsigned integers may be removed in the future
+ let _b : u8 = a; // for infering variable a to u8.
+
+ -a;
+ //~^ ERROR unary negation of unsigned integers may be removed in the future
+
+ let _d = -1u8;
+ //~^ ERROR unary negation of unsigned integers may be removed in the future
+
+ for _ in -10..10u8 {}
+ //~^ ERROR unary negation of unsigned integers may be removed in the future
+
+ -S; // should not trigger the gate; issue 26840
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[no_debug] //~ ERROR the `#[no_debug]` attribute is
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[omit_gdb_pretty_printer_section] //~ ERROR the `#[omit_gdb_pretty_printer_section]` attribute is
+fn main() {}
fn main() {
use std::boxed::HEAP;
- let x = box (HEAP) 'c'; //~ ERROR placement-in expression syntax is experimental
- //~^ WARN deprecated syntax
- println!("x: {}", x);
-
let x = in HEAP { 'c' }; //~ ERROR placement-in expression syntax is experimental
println!("x: {}", x);
}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-fn main() {
- let c = push_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
- let c = pop_unsafe!('c'); //~ ERROR push/pop_unsafe macros are experimental
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// FIXME #20661: format_args! emits calls to the unstable std::fmt::rt
-// module, so the compiler has some hacks to make that possible
-// (in span_is_internal). Unnfortunately those hacks defeat this
-// particular scenario of checking feature gates in arguments to
-// println!().
-
-// ignore-test
-
// tests that input to a macro is checked for use of gated features. If this
// test succeeds due to the acceptance of a feature, pick a new feature to
// test. Not ideal, but oh well :(
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that we get an expansion stack for `for` loops.
-
-// error-pattern:in this expansion of for loop expansion
-
-fn main() {
- for t in &foo {
- }
-}
// for-loops are expanded in the front end, and use an `iter` ident in their expansion. Check that
// `iter` is not accessible inside the for loop.
-#![allow(unstable)]
-
fn main() {
for _ in 0..10 {
iter.next(); //~ error: unresolved name `iter`
// except according to those terms.
fn main() {
- for
- &1 //~ ERROR refutable pattern in `for` loop binding
- in [1].iter() {}
+ for &1 in [1].iter() {} //~ ERROR refutable pattern in `for` loop binding
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ fn f(a: [u8; u32::DOESNOTEXIST]) {}
+ //~^ ERROR unresolved path in constant expression
+}
#![feature(placement_in_syntax)]
fn main() {
- box ( () ) 0;
+ in () { 0 };
//~^ ERROR: the trait `core::ops::Placer<_>` is not implemented
- //~| WARN deprecated syntax
}
for n in 0..1 {
println!("{}", f!()); //~ ERROR unresolved name `n`
}
+
+ if let Some(n) = None {
+ println!("{}", f!()); //~ ERROR unresolved name `n`
+ }
+
+ if false {
+ } else if let Some(n) = None {
+ println!("{}", f!()); //~ ERROR unresolved name `n`
+ }
+
+ while let Some(n) = None {
+ println!("{}", f!()); //~ ERROR unresolved name `n`
+ }
}
fn main() {
let values: Vec<u8> = vec![1,2,3,4,5,6,7,8];
- for
- [x,y,z]
-//~^ ERROR refutable pattern in `for` loop binding: `[]` not covered
- in values.chunks(3).filter(|&xs| xs.len() == 3) {
+ for [x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
+ //~^ ERROR refutable pattern in `for` loop binding: `[]` not covered
println!("y={}", y);
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct TS ( //~ ERROR empty tuple structs and enum variants are not allowed
+ #[cfg(untrue)]
+ int,
+);
+
+fn main() {
+ let s = S;
+}
// Test that the parser does not attempt to parse struct literals
// within assignments in if expressions.
+#![allow(unused_parens)]
+
struct Foo {
foo: usize
}
struct Foo;
impl Foo {
- #[unstable(feature = "test_feature")]
- #[deprecated(since = "1.0.0")]
+ #[unstable(feature = "test_feature", issue = "0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
fn foo(self) {}
}
// except according to those terms.
// Test that we can parse a unit struct with a where clause, even if
-// it leads to a error later on since `T` is unused.
+// it leads to an error later on since `T` is unused.
struct Foo<T> where T: Copy; //~ ERROR parameter `T` is never used
b.foo(&0)
//~^ ERROR the trait `Foo` is not implemented for the type `Bar`
//~| ERROR E0038
+ //~| WARNING E0038
}
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Test that when a crate is linked under another name that that name is used in global paths
+//! Test that when a crate is linked under another name that name is used in global paths
extern crate core as bar;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Also works as a test for #14564
+
+#[allow(non_snake_case)]
+mod Foo { }
+//~^ NOTE first definition of type or module `Foo`
+
+#[allow(dead_code)]
+struct Foo;
+//~^ WARNING duplicate definition of type or module `Foo`
+
+
+#[allow(non_snake_case)]
+mod Bar { }
+//~^ NOTE first definition of type or module `Bar`
+
+#[allow(dead_code)]
+struct Bar(i32);
+//~^ WARNING duplicate definition of type or module `Bar`
+
+
+#[allow(dead_code)]
+struct Baz(i32);
+//~^ NOTE first definition of type or module
+
+#[allow(non_snake_case)]
+mod Baz { }
+//~^ WARNING duplicate definition of type or module `Baz`
+
+
+#[allow(dead_code)]
+struct Qux { x: bool }
+//~^ NOTE first definition of type or module
+
+#[allow(non_snake_case)]
+mod Qux { }
+//~^ WARNING duplicate definition of type or module `Qux`
+
+
+#[allow(dead_code)]
+struct Quux;
+//~^ NOTE first definition of type or module
+
+#[allow(non_snake_case)]
+mod Quux { }
+//~^ WARNING duplicate definition of type or module `Quux`
+
+
+#[allow(dead_code)]
+enum Corge { A, B }
+
+#[allow(non_snake_case)]
+mod Corge { }
+//~^ ERROR duplicate definition of type or module `Corge`
+
+fn main() { }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![deny(unused_variables)]
+
+fn f(_: i32) {}
+
+fn main() {
+ let mut v = 0;
+ f(v);
+ v = match 0 { a => 0 }; //~ ERROR: unused variable: `a`
+ f(v);
+}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-trait Wrap<'b> {
- fn foo(&'b mut self);
-}
-
-struct Wrapper<P>(P);
-
-impl<'b, P> Wrap<'b> for Wrapper<P>
-where P: Process<'b>,
- <P as Process<'b>>::Item: Iterator {
- fn foo(&mut self) {}
-}
-
-
-pub trait Process<'a> {
- type Item;
- fn bar(&'a self);
-}
-
-fn push_process<P>(process: P) where P: Process<'static> {
- let _: Box<for<'b> Wrap<'b>> = Box::new(Wrapper(process));
- //~^ ERROR the trait `for<'b> Process<'b>` is not implemented for the type `P` [E0277]
- //~| ERROR the trait `for<'b> core::iter::Iterator` is not implemented for the type
- //~| ERROR cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting
-}
-
-fn main() {}
}
fn main() {
- let ex = (|x| {
+ let ex = |x| {
let_(add(x,x), |y| { //~ ERROR unable to infer enough type information about `_`
- let_(add(x, x), |x|x)})});
+ let_(add(x, x), |x|x)})};
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait A: Copy {}
+
+struct Foo;
+
+pub trait D {
+ fn f<T>(self)
+ where T<Bogus = Foo>: A;
+ //~^ ERROR associated type bindings are not allowed here [E0229]
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait A: Copy {}
+
+pub trait D {
+ fn f<T>(self)
+ where T<Bogus = Self::AlsoBogus>: A;
+ //~^ ERROR associated type bindings are not allowed here [E0229]
+}
+
+fn main() {}
self.pos += 1;
Some(next_val)
} else {
- let next_val = (self.mem[0] + self.mem[1]);
+ let next_val = self.mem[0] + self.mem[1];
self.mem[0] = self.mem[1];
self.mem[1] = next_val;
Some(next_val)
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+struct S;
+
+impl S {
+ const N: usize = 3;
+}
+
+static STUFF: [u8; S::N] = [0; S::N];
+//~^ ERROR array length constant evaluation error: unresolved path in constant expression
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait MapLookup<Q> {
+ type MapValue;
+}
+
+impl<K> MapLookup<K> for K {
+ type MapValue = K;
+}
+
+trait Map: MapLookup<<Self as Map>::Key> {
+ type Key;
+}
+
+impl<K> Map for K {
+ type Key = K;
+}
+
+
+fn main() {
+ let _ = &()
+ as &Map<Key=u32,MapValue=u32>;
+ //~^ ERROR the trait `Map` cannot be made into an object
+ //~| NOTE the trait cannot use `Self` as a type parameter
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ match 'a' {
+ char{ch} => true
+ //~^ ERROR `char` does not name a struct or a struct variant
+ };
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::sync::{self, Arc}; //~ NOTE previous import
+ //~^ NOTE previous import
+use std::sync::Arc; //~ ERROR a type named
+use std::sync; //~ ERROR a module named
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unsize, coerce_unsized)]
+
+// Verfies that non-PhantomData ZSTs still cause coercions to fail.
+// They might have additional semantics that we don't want to bulldoze.
+
+use std::marker::{Unsize, PhantomData};
+use std::ops::CoerceUnsized;
+
+struct NotPhantomData<T: ?Sized>(PhantomData<T>);
+
+struct MyRc<T: ?Sized> {
+ _ptr: *const T,
+ _boo: NotPhantomData<T>,
+}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<MyRc<U>> for MyRc<T>{ } //~ERROR
+
+fn main() {
+ let data = [1, 2, 3];
+ let iter = data.iter();
+ let x = MyRc { _ptr: &iter, _boo: NotPhantomData(PhantomData) };
+ let _y: MyRc<Iterator<Item=&u32>> = x;
+}
+
let Foo { .. } = x; //~ ERROR `Foo` does not name a struct
let x = Bar;
- Bar { ..x }; //~ ERROR `Bar` does not name a structure
- let Bar { .. } = x; //~ ERROR `Bar` does not name a struct
+ Bar { ..x }; //~ ERROR empty structs and enum variants with braces are unstable
+ let Bar { .. } = x; //~ ERROR empty structs and enum variants with braces are unstable
match Enum::Bar {
Enum::Bar { .. } //~ ERROR `Enum::Bar` does not name a struct
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let i = 5;
+ let index = 6;
+
+ match i {
+ 0...index => println!("winner"),
+ //~^ ERROR paths in constants may only refer to constants or functions
+ //~| ERROR non-constant path in constant expression
+ _ => println!("hello"),
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Unstable entities should be caught in import lists
+
+// aux-build:lint_stability.rs
+
+#![allow(unused_imports)]
+
+extern crate lint_stability;
+
+use lint_stability::{unstable, deprecated}; //~ ERROR use of unstable library feature 'test_feature'
+//~^ WARNING use of deprecated item
+
+use lint_stability::unstable::{self as u}; //~ ERROR use of unstable library feature 'test_feature'
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc.
+
+use foo::{}; //~ ERROR failed to resolve. foo
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc.
+
+mod m {
+ mod n {}
+}
+
+use m::n::{}; //~ ERROR module `n` is private
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc.
+
+// aux-build:lint_stability.rs
+
+extern crate lint_stability;
+
+use lint_stability::UnstableStruct::{}; //~ ERROR use of unstable library feature 'test_feature'
+use lint_stability::StableStruct::{}; // OK
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+enum bird {
+ pub duck,
+ //~^ ERROR: expected identifier, found keyword `pub`
+ //~^^ ERROR: expected
+ goose
+}
+
+
+fn main() {
+ let y = bird::goose;
+}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that the visibility modifier is included in the span of foreign items.
+
+extern {
+ fn foo();
+
+ pub //~ ERROR duplicate definition
+ fn foo();
+
+ pub //~ ERROR duplicate definition
+ static mut foo: u32;
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Foo<RHS=Self> {
+ type Assoc;
+}
+
+pub trait Bar: Foo<Assoc=()> {
+ fn new(&self, b: &
+ Bar //~ ERROR the trait `Bar` cannot be made into an object
+ <Assoc=()>
+ );
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ptr;
+
+fn main() {
+ (&ptr::write)(1 as *mut _, 42); //~ ERROR E0133
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct A;
+
+fn main() {
+ let a = A;
+
+ a + a; //~ ERROR binary operation `+` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::Add` might be missing for `A`
+
+ a - a; //~ ERROR binary operation `-` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::Sub` might be missing for `A`
+
+ a * a; //~ ERROR binary operation `*` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::Mul` might be missing for `A`
+
+ a / a; //~ ERROR binary operation `/` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::Div` might be missing for `A`
+
+ a % a; //~ ERROR binary operation `%` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::Rem` might be missing for `A`
+
+ a & a; //~ ERROR binary operation `&` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::BitAnd` might be missing for `A`
+
+ a | a; //~ ERROR binary operation `|` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::BitOr` might be missing for `A`
+
+ a << a; //~ ERROR binary operation `<<` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::Shl` might be missing for `A`
+
+ a >> a; //~ ERROR binary operation `>>` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::ops::Shr` might be missing for `A`
+
+ a == a; //~ ERROR binary operation `==` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::cmp::PartialEq` might be missing for `A`
+
+ a != a; //~ ERROR binary operation `!=` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::cmp::PartialEq` might be missing for `A`
+
+ a < a; //~ ERROR binary operation `<` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A`
+
+ a <= a; //~ ERROR binary operation `<=` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A`
+
+ a > a; //~ ERROR binary operation `>` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A`
+
+ a >= a; //~ ERROR binary operation `>=` cannot be applied to type `A`
+ //~^ NOTE an implementation of `std::cmp::PartialOrd` might be missing for `A`
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::rc::Rc;
+use std::sync::Arc;
+
+struct Foo<'a>(&'a String);
+
+impl<'a> Drop for Foo<'a> {
+ fn drop(&mut self) {
+ println!("{:?}", self.0);
+ }
+}
+
+fn main() {
+ {
+ let (y, x);
+ x = "alive".to_string();
+ y = Arc::new(Foo(&x)); //~ ERROR `x` does not live long enough
+ }
+
+ {
+ let (y, x);
+ x = "alive".to_string();
+ y = Rc::new(Foo(&x)); //~ ERROR `x` does not live long enough
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod a {
+ struct A;
+
+ impl Default for A {
+ pub fn default() -> A {
+ //~^ ERROR E0449
+ A;
+ }
+ }
+}
+
+
+fn main() {
+ a::A::default();
+ //~^ ERROR method `default` is inaccessible
+ }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:issue-29181.rs
+
+extern crate issue_29181 as foo;
+
+fn main() {
+ 0.homura(); //~ ERROR no method named `homura` found
+}
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x: typeof(92) = 92; //~ ERROR `typeof` is a reserved keyword
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use zoo::bird::{duck, goose};
-
-mod zoo {
- pub enum bird {
- pub duck, //~ ERROR: unnecessary `pub` visibility
- goose
- }
-}
-
-
-fn main() {
- let y = goose;
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Creating a stack closure which references an box and then
+// Creating a stack closure which references a box and then
// transferring ownership of the box before invoking the stack
// closure results in a crash.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![deny(const_err)]
+
use std::{isize, i8, i16, i32, i64};
use std::thread;
fn main() {
assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err());
- //~^ ERROR attempted to divide with overflow in a constant expression
+ //~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err());
- //~^ ERROR attempted to divide with overflow in a constant expression
+ //~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err());
- //~^ ERROR attempted to divide with overflow in a constant expression
+ //~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err());
- //~^ ERROR attempted to divide with overflow in a constant expression
+ //~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err());
- //~^ ERROR attempted to divide with overflow in a constant expression
+ //~^ ERROR attempted to divide with overflow
assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err());
- //~^ ERROR attempted to divide by zero in a constant expression
+ //~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err());
- //~^ ERROR attempted to divide by zero in a constant expression
+ //~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err());
- //~^ ERROR attempted to divide by zero in a constant expression
+ //~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err());
- //~^ ERROR attempted to divide by zero in a constant expression
+ //~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err());
- //~^ ERROR attempted to divide by zero in a constant expression
+ //~^ ERROR attempted to divide by zero
assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err());
- //~^ ERROR attempted remainder with overflow in a constant expression
+ //~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err());
- //~^ ERROR attempted remainder with overflow in a constant expression
+ //~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err());
- //~^ ERROR attempted remainder with overflow in a constant expression
+ //~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err());
- //~^ ERROR attempted remainder with overflow in a constant expression
+ //~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err());
- //~^ ERROR attempted remainder with overflow in a constant expression
+ //~^ ERROR attempted remainder with overflow
assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err());
- //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+ //~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err());
- //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+ //~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err());
- //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+ //~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err());
- //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+ //~^ ERROR attempted remainder with a divisor of zero
assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err());
- //~^ ERROR attempted remainder with a divisor of zero in a constant expression
+ //~^ ERROR attempted remainder with a divisor of zero
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Example taken from RFC 1238 text
+
+// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
+// #examples-of-code-that-will-start-to-be-rejected
+
+// Compare against test/run-pass/issue28498-must-work-ex2.rs
+
+use std::cell::Cell;
+
+struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+
+struct Foo<T> { data: Vec<T> }
+
+fn potentially_specialized_wrt_t<T>(t: &T) {
+ // Hypothetical code that does one thing for generic T and then is
+ // specialized for T == Concrete (and the specialized form can
+ // then access a reference held in concrete tuple).
+ //
+ // (We don't have specialization yet, but we want to allow for it
+ // in the future.)
+}
+
+impl<T> Drop for Foo<T> {
+ fn drop(&mut self) {
+ potentially_specialized_wrt_t(&self.data[0])
+ }
+}
+
+fn main() {
+ let mut foo = Foo { data: Vec::new() };
+ foo.data.push(Concrete(0, Cell::new(None)));
+ foo.data.push(Concrete(0, Cell::new(None)));
+
+ foo.data[0].1.set(Some(&foo.data[1]));
+ //~^ ERROR `foo.data` does not live long enough
+ foo.data[1].1.set(Some(&foo.data[0]));
+ //~^ ERROR `foo.data` does not live long enough
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Demonstrate that having a lifetime param causes dropck to reject code
+// that might indirectly access previously dropped value.
+//
+// Compare with run-pass/issue28498-ugeh-with-lifetime-param.rs
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<'a>(u32, &'a ScribbleOnDrop);
+
+impl<'a> Drop for Foo<'a> {
+ fn drop(&mut self) {
+ // Use of `unsafe_destructor_blind_to_params` is unsound,
+ // because destructor accesses borrowed data in `self.1`
+ // and we must force that to strictly outlive `self`.
+ println!("Dropping Foo({}, {:?})", self.0, self.1);
+ }
+}
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped);
+ //~^ ERROR `last_dropped` does not live long enough
+ foo1 = Foo(1, &first_dropped);
+ //~^ ERROR `first_dropped` does not live long enough
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Demonstrate that a type param in negative position causes dropck to reject code
+// that might indirectly access previously dropped value.
+//
+// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
+
+impl<T> Drop for Foo<T> {
+ fn drop(&mut self) {
+ // Use of `unsafe_destructor_blind_to_params` is unsound,
+ // because we pass `T` to the callback in `self.2`
+ // below, and thus potentially read from borrowed data.
+ println!("Dropping Foo({}, {})", self.0, (self.2)(&self.1));
+ }
+}
+
+fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped, Box::new(callback));
+ //~^ ERROR `last_dropped` does not live long enough
+ foo1 = Foo(1, &first_dropped, Box::new(callback));
+ //~^ ERROR `first_dropped` does not live long enough
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Demonstrate that having a trait bound causes dropck to reject code
+// that might indirectly access previously dropped value.
+//
+// Compare with run-pass/issue28498-ugeh-with-trait-bound.rs
+
+use std::fmt;
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T:fmt::Debug>(u32, T);
+
+impl<T:fmt::Debug> Drop for Foo<T> {
+ fn drop(&mut self) {
+ // Use of `unsafe_destructor_blind_to_params` is unsound,
+ // because we access `T` fmt method when we pass `self.1`
+ // below, and thus potentially read from borrowed data.
+ println!("Dropping Foo({}, {:?})", self.0, self.1);
+ }
+}
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped);
+ //~^ ERROR `last_dropped` does not live long enough
+ foo1 = Foo(1, &first_dropped);
+ //~^ ERROR `first_dropped` does not live long enough
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
#![feature(foo)] //~ ERROR unused or unknown feature
extern crate lint_output_format; //~ ERROR use of unstable library feature
-use lint_output_format::{foo, bar};
+use lint_output_format::{foo, bar}; //~ ERROR use of unstable library feature
+//~^ WARNING use of deprecated item: text,
fn main() {
let _x = foo(); //~ WARNING #[warn(deprecated)] on by default
inherit: u8,
#[unstable(feature = "test_feature", issue = "0")]
override1: u8,
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
override2: u8,
}
struct Stable2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")] u8);
+ #[deprecated(since = "1.0.0", reason = "text")] u8);
#[unstable(feature = "test_feature", issue = "0")]
struct Unstable {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
override1: u8,
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test_feature", issue = "0")]
override2: u8,
}
struct Unstable2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")] u8);
+ #[deprecated(since = "1.0.0", reason = "text")] u8);
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(feature = "rust1", since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
struct Deprecated {
inherit: u8,
#[stable(feature = "rust1", since = "1.0.0")]
}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(feature = "rust1", since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
struct Deprecated2(u8,
#[stable(feature = "rust1", since = "1.0.0")] u8,
#[unstable(feature = "test_feature", issue = "0")] u8);
mod this_crate {
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub fn deprecated() {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stable() {}
- #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn stable_text() {}
#[stable(feature = "rust1", since = "1.0.0")]
impl MethodTester {
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub fn method_deprecated(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable(&self) {}
- #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
+ #[stable(feature = "rust1", since = "1.0.0")]
pub fn method_stable_text(&self) {}
}
pub trait Trait {
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
fn trait_deprecated(&self) {}
#[unstable(feature = "test_feature", issue = "0")]
#[deprecated(since = "1.0.0", reason = "text")]
#[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable(&self) {}
- #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
+ #[stable(feature = "rust1", since = "1.0.0")]
fn trait_stable_text(&self) {}
}
impl Trait for MethodTester {}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedStruct {
#[stable(feature = "test_feature", since = "1.0.0")] i: isize
}
}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedUnitStruct;
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableUnitStruct;
pub enum Enum {
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
DeprecatedVariant,
#[unstable(feature = "test_feature", issue = "0")]
UnstableVariant,
}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub struct DeprecatedTupleStruct(isize);
#[unstable(feature = "test_feature", issue = "0")]
pub struct UnstableTupleStruct(isize);
}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
fn test_fn_body() {
fn fn_in_body() {}
fn_in_body();
impl MethodTester {
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
fn test_method_body(&self) {
fn fn_in_body() {}
fn_in_body();
}
#[unstable(feature = "test_feature", issue = "0")]
- #[deprecated(since = "1.0.0")]
+ #[deprecated(since = "1.0.0", reason = "text")]
pub trait DeprecatedTrait {
fn dummy(&self) { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![deny(visible_private_types)]
#![allow(dead_code)]
#![crate_type="lib"]
}
fn main() {
- if (1 == 2) { forever(); }
+ if 1 == 2 { forever(); }
}
#![feature(box_syntax)]
fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
- box() (x, x) //~ ERROR use of moved value
- //~^ WARN deprecated syntax
+ box (x, x) //~ ERROR use of moved value
}
fn main() {
dup(box 3);
#[derive(Debug)]
struct SExpr<'x> {
elements: Vec<Box<Expr+ 'x>>,
+ //~^ ERROR E0038
}
impl<'x> PartialEq for SExpr<'x> {
fn eq(&self, other:&SExpr<'x>) -> bool {
println!("L1: {} L2: {}", self.elements.len(), other.elements.len());
- //~^ ERROR E0038
+
let result = self.elements.len() == other.elements.len();
println!("Got compare {}", result);
}
fn main() {
- let a: Box<Expr> = Box::new(SExpr::new()); //~ ERROR E0038
- let b: Box<Expr> = Box::new(SExpr::new()); //~ ERROR E0038
+ let a: Box<Expr> = Box::new(SExpr::new());
+ let b: Box<Expr> = Box::new(SExpr::new());
// assert_eq!(a , b);
}
}
fn make_baz<T:Baz>(t: &T) -> &Baz {
+ //~^ ERROR E0038
+ //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing
t
- //~^ ERROR E0038
- //~| NOTE the trait cannot use `Self` as a type parameter in the supertrait listing
}
fn main() {
// the error points to the start of the file, not the line with the
// transmute
-// error-pattern: transmute called on types with different size
+// error-pattern: transmute called with differently sized types
use std::mem;
// the error points to the start of the file, not the line with the
// transmute
-// error-pattern: transmute called on types with different size
+// error-pattern: transmute called with differently sized types
use std::mem;
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that placement in respects unsafe code checks.
+
+#![feature(box_heap)]
+#![feature(placement_in_syntax)]
+
+fn main() {
+ use std::boxed::HEAP;
+
+ let p: *const i32 = &42;
+ let _ = in HEAP { *p }; //~ ERROR requires unsafe
+
+ let p: *const _ = &HEAP;
+ let _ = in *p { 42 }; //~ ERROR requires unsafe
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that placement in respects unstable code checks.
+
+#![feature(placement_in_syntax)]
+#![feature(core)]
+
+extern crate core;
+
+fn main() {
+ use std::boxed::HEAP; //~ ERROR use of unstable library feature
+
+ let _ = in HEAP { //~ ERROR use of unstable library feature
+ ::core::raw::Slice { //~ ERROR use of unstable library feature
+ data: &42, //~ ERROR use of unstable library feature
+ len: 1 //~ ERROR use of unstable library feature
+ }
+ };
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test to ensure private traits are inaccessible with UFCS angle-bracket syntax.
+
+mod foo {
+ trait Bar {
+ fn baz() {}
+ }
+
+ impl Bar for i32 {}
+}
+
+fn main() {
+ <i32 as ::foo::Bar>::baz(); //~ERROR method `baz` is inaccessible
+ //~^NOTE: trait `Bar` is private
+}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Basic sanity check for `push_unsafe!(EXPR)` and
-// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
-// positive number of pushes in the stack, or if we are within a
-// normal `unsafe` block, but otherwise cannot.
-
-#![feature(pushpop_unsafe)]
-
-static mut X: i32 = 0;
-
-unsafe fn f() { X += 1; return; }
-fn g() { unsafe { X += 1_000; } return; }
-
-fn main() {
- push_unsafe!( {
- f(); pop_unsafe!({
- f() //~ ERROR: call to unsafe function
- })
- } );
-
- push_unsafe!({
- f();
- pop_unsafe!({
- g();
- f(); //~ ERROR: call to unsafe function
- })
- } );
-
- push_unsafe!({
- g(); pop_unsafe!({
- unsafe {
- f();
- }
- f(); //~ ERROR: call to unsafe function
- })
- });
-
-
- // Note: For implementation simplicity the compiler just
- // ICE's if you underflow the push_unsafe stack.
- //
- // Thus all of the following cases cause an ICE.
- //
- // (The "ERROR" notes are from an earlier version
- // that used saturated arithmetic rather than checked
- // arithmetic.)
-
- // pop_unsafe!{ g() };
- //
- // push_unsafe!({
- // pop_unsafe!(pop_unsafe!{ g() })
- // });
- //
- // push_unsafe!({
- // g();
- // pop_unsafe!(pop_unsafe!({
- // f() // ERROR: call to unsafe function
- // }))
- // });
- //
- // pop_unsafe!({
- // f(); // ERROR: call to unsafe function
- // })
-
-}
}
fn with_assoc<'a,'b>() {
- // We get an error because beacuse 'b:'a does not hold:
+ // We get an error because 'b:'a does not hold:
let _: &'a WithHrAssoc<TheType<'b>> = loop { };
//~^ ERROR reference has a longer lifetime
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// More checks that stability attributes are used correctly
+
+#![feature(staged_api)]
+#![staged_api]
+
+#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR multiple 'feature' items
+fn f1() { }
+
+#[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse'
+fn f2() { }
+
+#[unstable(feature = "a", issue = "no")] //~ ERROR incorrect 'issue'
+fn f3() { }
+
+fn main() { }
#![staged_api]
mod bogus_attribute_types_1 {
- #[stable(feature = "a", since = "a", reason)] //~ ERROR incorrect meta item
+ #[stable(feature = "a", since = "a", reason)] //~ ERROR unknown meta item 'reason'
fn f1() { }
- #[stable(feature = "a", since, reason = "a")] //~ ERROR incorrect meta item
+ #[stable(feature = "a", since)] //~ ERROR incorrect meta item
fn f2() { }
- #[stable(feature, since = "a", reason = "a")] //~ ERROR incorrect meta item
+ #[stable(feature, since = "a")] //~ ERROR incorrect meta item
fn f3() { }
- #[stable(feature = "a", since = "a", reason(b))] //~ ERROR incorrect meta item
- fn f4() { }
-
- #[stable(feature = "a", since(b), reason = "a")] //~ ERROR incorrect meta item
+ #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item
fn f5() { }
- #[stable(feature(b), since = "a", reason = "a")] //~ ERROR incorrect meta item
+ #[stable(feature(b), since = "a")] //~ ERROR incorrect meta item
fn f6() { }
}
}
mod missing_feature_names {
- #[unstable(since = "a", issue = "0")] //~ ERROR missing 'feature'
+ #[unstable(issue = "0")] //~ ERROR missing 'feature'
fn f1() { }
- #[unstable(feature = "a")]
- fn f2() { } //~ ERROR need to point to an issue
+ #[unstable(feature = "a")] //~ ERROR missing 'issue'
+ fn f2() { }
#[stable(since = "a")] //~ ERROR missing 'feature'
fn f3() { }
fn f2() { }
}
-#[unstable(feature = "a", since = "b", issue = "0")]
+#[unstable(feature = "a", issue = "0")]
#[stable(feature = "a", since = "b")]
fn multiple1() { } //~ ERROR multiple stability levels
-#[unstable(feature = "a", since = "b", issue = "0")]
-#[unstable(feature = "a", since = "b", issue = "0")]
+#[unstable(feature = "a", issue = "0")]
+#[unstable(feature = "a", issue = "0")]
fn multiple2() { } //~ ERROR multiple stability levels
#[stable(feature = "a", since = "b")]
fn multiple3() { } //~ ERROR multiple stability levels
#[stable(feature = "a", since = "b")]
-#[deprecated(since = "b")]
-#[deprecated(since = "b")]
+#[deprecated(since = "b", reason = "text")]
+#[deprecated(since = "b", reason = "text")]
fn multiple4() { } //~ ERROR multiple deprecated attributes
//~^ ERROR Invalid stability or deprecation version found
-#[deprecated(since = "a")]
+#[deprecated(since = "a", reason = "text")]
fn deprecated_without_unstable_or_stable() { } //~ ERROR deprecated attribute must be paired
fn main() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo(); //~ ERROR empty tuple structs and enum variants are not allowed
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod m {
+ trait Priv {
+ fn f(&self) {}
+ }
+ impl Priv for super::S {}
+ pub trait Pub: Priv {}
+}
+
+struct S;
+impl m::Pub for S {}
+
+fn g<T: m::Pub>(arg: T) {
+ arg.f(); //~ ERROR: source trait is private
+}
+
+fn main() {
+ g(S);
+}
//~^ ERROR E0038
//~| ERROR E0038
//~| ERROR E0277
+ //~| WARNING E0038
}
unsafe fn f() {
let _: i8 = transmute(16i16);
- //~^ ERROR transmute called on types with different sizes
+ //~^ ERROR transmute called with differently sized types
}
unsafe fn g<T>(x: &T) {
let _: i8 = transmute(x);
- //~^ ERROR transmute called on types with potentially different sizes
+ //~^ ERROR transmute called with differently sized types
}
fn main() {}
use std::mem::transmute;
fn a<T, U: ?Sized>(x: &[T]) -> &U {
- unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+ unsafe { transmute(x) } //~ ERROR transmute called with differently sized types
}
fn b<T: ?Sized, U: ?Sized>(x: &T) -> &U {
- unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+ unsafe { transmute(x) } //~ ERROR transmute called with differently sized types
}
fn c<T, U>(x: &T) -> &U {
}
fn e<T: ?Sized, U>(x: &T) -> &U {
- unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+ unsafe { transmute(x) } //~ ERROR transmute called with differently sized types
}
fn f<T, U: ?Sized>(x: &T) -> &U {
- unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+ unsafe { transmute(x) } //~ ERROR transmute called with differently sized types
}
fn main() { }
fn n(x: &T) -> &isize {
// Not OK here, because T : Sized is not in scope.
- unsafe { transmute(x) } //~ ERROR transmute called on types with potentially different sizes
+ unsafe { transmute(x) } //~ ERROR transmute called with differently sized types
}
}
//~^ ERROR mutating transmuted &mut T from &T may cause undefined behavior
}
-
use std::marker::PhantomData;
-// A erroneous variant of `run-pass/unboxed_closures-infer-recursive-fn.rs`
+// An erroneous variant of `run-pass/unboxed_closures-infer-recursive-fn.rs`
// where we attempt to perform mutation in the recursive function. This fails to compile
// because it winds up requiring `FnMut` which enforces linearity.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A quick test of 'unsafe const fn' functionality
+
+#![feature(const_fn)]
+
+const unsafe fn dummy(v: u32) -> u32 {
+ !v
+}
+
+const VAL: u32 = dummy(0xFFFF); //~ ERROR E0133
+
+fn main() {
+ assert_eq!(VAL, 0xFFFF0000);
+}
+
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct A { pub i: isize }
-pub enum C { pub Variant } //~ ERROR: unnecessary `pub`
-
-pub trait E {
- fn foo(&self);
-}
-
-impl E for A {
- pub fn foo(&self) {} //~ ERROR: unnecessary visibility
-}
-
-fn main() {}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct A { pub i: isize }
+
+pub trait E {
+ fn foo(&self);
+}
+
+impl E for A {
+ pub fn foo(&self) {} //~ ERROR: unnecessary visibility
+}
+
+fn main() {}
// Invariance is a trap from which NO ONE CAN ESCAPE.
// In other words, even though the `&'b isize` occurs in
-// a argument list (which is contravariant), that
+// an argument list (which is contravariant), that
// argument list occurs in an invariant context.
#[rustc_variance]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![deny(bivariance)]
#![allow(dead_code)]
#![feature(rustc_attrs)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![deny(bivariance)]
#![allow(dead_code)]
#![feature(rustc_attrs)]
use id::Id;
mod s {
- #![allow(unstable)]
use std::sync::atomic::{AtomicUsize, Ordering};
static S_COUNT: AtomicUsize = AtomicUsize::new(0);
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A method's receiver must be well-formed, even if it has late-bound regions.
+// Because of this, a method's substs being well-formed does not imply that
+// the method's implied bounds are met.
+
+struct Foo<'b>(Option<&'b ()>);
+
+trait Bar<'b> {
+ fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32;
+}
+
+impl<'b> Bar<'b> for Foo<'b> {
+ fn xmute<'a>(&'a self, u: &'b u32) -> &'a u32 { u }
+}
+
+fn main() {
+ let f = Foo(None);
+ let f2 = f;
+ let dangling = {
+ let pointer = Box::new(42);
+ f2.xmute(&pointer) //~ ERROR `pointer` does not live long enough
+ };
+ println!("{}", dangling);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that misc. method calls are well-formed
+
+use std::marker::PhantomData;
+use std::ops::{Deref, Shl};
+
+#[derive(Copy, Clone)]
+struct S<'a, 'b: 'a> {
+ marker: PhantomData<&'a &'b ()>,
+ bomb: Option<&'b u32>
+}
+
+type S2<'a> = S<'a, 'a>;
+
+impl<'a, 'b> S<'a, 'b> {
+ fn transmute_inherent(&self, a: &'b u32) -> &'a u32 {
+ a
+ }
+}
+
+fn return_dangling_pointer_inherent(s: S2) -> &u32 {
+ let s = s;
+ s.transmute_inherent(&mut 42) //~ ERROR does not live long enough
+}
+
+impl<'a, 'b> Deref for S<'a, 'b> {
+ type Target = &'a u32;
+ fn deref(&self) -> &&'a u32 {
+ self.bomb.as_ref().unwrap()
+ }
+}
+
+fn return_dangling_pointer_coerce(s: S2) -> &u32 {
+ let four = 4;
+ let mut s = s;
+ s.bomb = Some(&four); //~ ERROR does not live long enough
+ &s
+}
+
+fn return_dangling_pointer_unary_op(s: S2) -> &u32 {
+ let four = 4;
+ let mut s = s;
+ s.bomb = Some(&four); //~ ERROR does not live long enough
+ &*s
+}
+
+impl<'a, 'b> Shl<&'b u32> for S<'a, 'b> {
+ type Output = &'a u32;
+ fn shl(self, t: &'b u32) -> &'a u32 { t }
+}
+
+fn return_dangling_pointer_binary_op(s: S2) -> &u32 {
+ let s = s;
+ s << &mut 3 //~ ERROR does not live long enough
+}
+
+fn return_dangling_pointer_method(s: S2) -> &u32 {
+ let s = s;
+ s.shl(&mut 3) //~ ERROR does not live long enough
+}
+
+fn return_dangling_pointer_ufcs(s: S2) -> &u32 {
+ let s = s;
+ S2::shl(s, &mut 3) //~ ERROR does not live long enough
+}
+
+fn main() {
+ let s = S { marker: PhantomData, bomb: None };
+ let _inherent_dp = return_dangling_pointer_inherent(s);
+ let _coerce_dp = return_dangling_pointer_coerce(s);
+ let _unary_dp = return_dangling_pointer_unary_op(s);
+ let _binary_dp = return_dangling_pointer_binary_op(s);
+ let _method_dp = return_dangling_pointer_method(s);
+ let _ufcs_dp = return_dangling_pointer_ufcs(s);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// check that static methods don't get to assume their trait-ref
+// is well-formed.
+// FIXME(#27579): this is just a bug. However, our checking with
+// static inherent methods isn't quite working - need to
+// fix that before removing the check.
+
+trait Foo<'a, 'b, T>: Sized {
+ fn make_me() -> Self { loop {} }
+ fn static_evil(u: &'b u32) -> &'a u32;
+}
+
+struct Evil<'a, 'b: 'a>(Option<&'a &'b ()>);
+
+impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
+ fn make_me() -> Self { }
+ fn static_evil(u: &'b u32) -> &'a u32 {
+ u //~ ERROR cannot infer an appropriate lifetime
+ }
+}
+
+struct IndirectEvil<'a, 'b: 'a>(Option<&'a &'b ()>);
+
+impl<'a, 'b> Foo<'a, 'b, ()> for IndirectEvil<'a, 'b> {
+ fn make_me() -> Self { IndirectEvil(None) }
+ fn static_evil(u: &'b u32) -> &'a u32 {
+ let me = Self::make_me(); //~ ERROR lifetime bound not satisfied
+ loop {} // (`me` could be used for the lifetime transmute).
+ }
+}
+
+impl<'a, 'b> Evil<'a, 'b> {
+ fn inherent_evil(u: &'b u32) -> &'a u32 {
+ u //~ ERROR cannot infer an appropriate lifetime
+ }
+}
+
+// while static methods don't get to *assume* this, we still
+// *check* that they hold.
+
+fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+ <()>::static_evil(b) //~ ERROR cannot infer an appropriate lifetime
+}
+
+fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+ <IndirectEvil>::static_evil(b)
+ //~^ ERROR cannot infer an appropriate lifetime
+}
+
+fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
+ <Evil>::inherent_evil(b) // bug? shouldn't this be an error
+}
+
+
+fn main() {}
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
trait TraitWithAssocType {
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// N.B. These are `mut` only so they don't constant fold away.
// gdb-command:continue
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// N.B. These are `mut` only so they don't constant fold away.
// gdb-command:continue
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// gdb-check:$28 = 9.25
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
static mut B: bool = false;
// lldb-check:[...]$12 = 3.5
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-check:[...]$12 = 3.5
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-check:[...]$2 = TheC
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
enum ABC { TheA, TheB, TheC }
// lldb-check:[...]$2 = TheOnlyCase(4820353753753434)
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct SomeStruct {
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
let stack_val_ref: &(i16, f32) = &stack_val;
let ref_to_unnamed: &(i16, f32) = &(-15, -20f32);
- let unique_val: Box<(i16, f32)> = box() (-17, -22f32);
+ let unique_val: Box<(i16, f32)> = box (-17, -22f32);
let unique_val_ref: &(i16, f32) = &*unique_val;
zzz(); // #break
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
let a = box 1;
- let b = box() (2, 3.5f64);
+ let b = box (2, 3.5f64);
zzz(); // #break
}
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct StructWithSomePadding {
// lldb-check:[...]$6 = Case1 { x: 0, y: 8970181431921507452 }
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Clone)]
// lldb-check:[...]$2 = (4444.5, 5555, 6666, 7777.5)
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
trait Trait {
// lldb-check:[...]$6 = (StructWithDrop { a: OneHundred, b: Vienna }, 9)
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::AnEnum::{OneHundred, OneThousand, OneMillion};
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::AutoDiscriminant::{One, Two, Three};
// lldb-command:continue
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn some_generic_fun<T1, T2>(a: T1, b: T2) -> (T2, T1) {
// compile-flags:-g
#![allow(dead_code, unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#![feature(const_fn)]
#![feature(static_mutex)]
// compile-flags:-g
#![allow(dead_code, unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// This test makes sure that the compiler doesn't crash when trying to assign
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// min-lldb-version: 310
// === GDB TESTS ===================================================================================
-// gdb-command:break cross_crate_spans.rs:23
+// gdb-command:break cross_crate_spans.rs:24
// gdb-command:run
// gdb-command:print result
// === LLDB TESTS ==================================================================================
-// lldb-command:b cross_crate_spans.rs:23
+// lldb-command:b cross_crate_spans.rs:24
// lldb-command:run
// lldb-command:print result
#![allow(unused_variables)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Univariant::Unit;
managed_box(&(34, 35));
borrowed_pointer(&(36, 37));
contained_borrowed_pointer((&38, 39));
- unique_pointer(box() (40, 41, 42));
+ unique_pointer(box (40, 41, 42));
ref_binding((43, 44, 45));
ref_binding_in_tuple((46, (47, 48)));
ref_binding_in_struct(Struct { a: 49, b: 50 });
#![allow(unused_variables)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
#![allow(unused_variables)]
#![feature(box_patterns)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Univariant::Unit;
let (&cc, _) = (&38, 39);
// unique pointer
- let box dd = box() (40, 41, 42);
+ let box dd = box (40, 41, 42);
// ref binding
let ref ee = (43, 44, 45);
// lldb-check:[...]$4 = StructPaddedAtEnd { x: [22, 23], y: [24, 25] }
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct NoPadding1 {
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn immediate_args(a: isize, b: bool, c: f64) {
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-command:continue
#![allow(dead_code, unused_assignments, unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[no_stack_check]
// lldb-command:continue
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn immediate_args(a: isize, b: bool, c: f64) {
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// This test case makes sure that we get correct type descriptions for the enum
// lldb-check:[...]$8 = ((5, Struct { a: 6, b: 7.5 }), (Struct { a: 6, b: 7.5 }, 5))
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Clone)]
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn outer<TA: Clone>(a: TA) {
// lldb-command:continue
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
// gdb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
// gdb-check:$4 = {{a = -1}}
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Regular::{Case1, Case2, Case3};
// lldb-check:[...]$3 = AGenericStruct<f64, generic_struct::AGenericStruct<i32, f64>> { key: 6.5, value: AGenericStruct<i32, f64> { key: 7, value: 8.5 } }
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct AGenericStruct<TKey, TValue> {
// lldb-command:print univariant
// lldb-check:[...]$3 = TheOnlyCase(-1)
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Regular::{Case1, Case2, Case3};
// lldb-command:continue
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// This test case makes sure that debug info does not ICE when include_str is
// gdb-command:run
// gdb-command:next
-// gdb-check:[...]34[...]s
+// gdb-check:[...]35[...]s
// gdb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// IF YOU MODIFY THIS FILE, BE CAREFUL TO ADAPT THE LINE NUMBERS IN THE DEBUGGER COMMANDS
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct ZeroSizedStruct;
// lldb-check:[...]$6 = 1000000
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-check:[...]$15 = -1
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-check:[...]$17 = 232
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
// lldb-check:[...]$5 = false
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-check:[...]$12 = 2
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-check:[...]$12 = 2
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
macro_rules! trivial {
#![allow(unused_variables)]
#![allow(unused_assignments)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
static mut MUT_INT: isize = 0;
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
// lldb-command:continue
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
// lldb-check:[...]$2 = 30303
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn function_one() {
// lldb-check:[...]$2 = 30303
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn function_one() {
// lldb-check:[...]$11 = 20
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// gdb-check:$2 = {<No data fields>}
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
enum ANilEnum {}
// gdb-command:continue
#![allow(unused_variables)]
+#![feature(no_debug)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn function_with_debuginfo() {
// lldb-check:[...]$9 = Nope
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// If a struct has exactly two variants, one of them is empty, and the other one
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[repr(packed)]
// lldb-check:[...]$5 = 40
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[repr(packed)]
// is taken from issue #11083.
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
pub struct Window<'a> {
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Opt::{Empty, Val};
// lldb-command:continue
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
// lldb-command:continue
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#[derive(Copy, Clone)]
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn a_function(x: bool, y: bool) {
// lldb-check:[...]$5 = 20
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// gdb-command:continue
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
#![feature(core_simd)]
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct NoPadding16 {
#![allow(unused_variables)]
#![allow(dead_code)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
static mut NO_PADDING_8: (i8, u8) = (-50, 50);
// lldb-check:[...]$4 = 5
// lldb-command:continue
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
// lldb-check:[...]$2 = TheOnlyCase(Struct { x: 123, y: 456, z: 789 })
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Regular::{Case1, Case2};
// lldb-check:[...]$7 = Tree { x: Simple { x: 25 }, y: InternalPaddingParent { x: InternalPadding { x: 26, y: 27 }, y: InternalPadding { x: 28, y: 29 }, z: InternalPadding { x: 30, y: 31 } }, z: BagInBag { x: Bag { x: Simple { x: 32 } } } }
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Simple {
// lldb-check:[...]$3 = TheOnlyCase { a: -1 }
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Regular::{Case1, Case2, Case3};
// lldb-check:[...]$3 = NestedOuter { a: NestedInner { a: WithDestructor { x: 7890, y: 9870 } } }
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct NoDestructor {
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
trait Trait {
// gdb-check:$10 = {x = {__0 = {__0 = 40, __1 = 41, __2 = 42}, __1 = {__0 = 43, __1 = 44}}, y = {__0 = 45, __1 = 46, __2 = 47, __3 = 48}}
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct NoPadding1 {
// lldb-check:[...]$6 = ((21, 22), 23)
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
fn main() {
// structs.
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct NoPadding16(u16, i16);
// lldb-check:[...]$3 = TheOnlyCase(-1)
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Regular::{Case1, Case2, Case3};
#![feature(box_syntax)]
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
use self::Enum1::{Variant1, Variant2};
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// compile-flags:-g
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
// No need to actually run the debugger, just make sure that the compiler can
#![allow(unused_variables)]
#![feature(box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
#![allow(unused_variables)]
#![feature(unboxed_closures, box_syntax)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
#![feature(unboxed_closures, box_syntax)]
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct Struct {
// lldb-check:[...]$5 = &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }]
#![allow(dead_code, unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
struct AStruct {
// lldb-check:[...]$0 = [1, 2, 3]
#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
static mut VECT: [i32; 3] = [1, 2, 3];
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn test(&'a str) {
+ //~^ ERROR unexpected lifetime `'a` in pattern
+}
+
+fn main() {
+}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-fn main() {
- box (1 + 1)
- //~^ HELP try using `box ()` instead:
- //~| SUGGESTION box () (1 + 1)
- //~| WARN deprecated syntax
- ; //~ ERROR expected expression, found `;`
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-struct Foo;
-
-fn f2() {
- let _end_stmt = Foo { };
- //~^ ERROR: structure literal must either have at least one field
-}
-
-fn main() {}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-struct Foo;
-
-fn g3() {
- let _mid_tuple = (Foo { }, 2);
- //~^ ERROR: structure literal must either have at least one field
-}
-
-fn main() {}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-struct Foo;
-
-fn h4() {
- let _end_of_tuple = (3, Foo { });
- //~^ ERROR: structure literal must either have at least one field
-}
-
-fn main() {}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-struct Foo;
-
-fn i5() {
- let _end_of_block = { Foo { } };
- //~^ ERROR: structure literal must either have at least one field
-}
-
-fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-struct Foo(); //~ ERROR unit-like struct definition should be written as `struct Foo;`
-
-fn main() {}
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-struct Foo {}
-//~^ ERROR: unit-like struct definition should be written as `struct Foo;`
-
-fn main() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z parse-only
-
-enum Foo {
- Bar {} //~ ERROR unit-like struct variant should be written without braces, as `Bar,`
-}
let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
let _ =
- (((&((([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3])
- as &[i32; 3]) as *const _ as *const [i32; 3]) as
- *const [i32; (3 as usize)] as *const [i32; 3]);
-
+ (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3])
+ as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)] as
+ *const [i32; 3]);
// error-pattern:stop
// #18576
-// Make sure that an calling extern function pointer in an unreachable
+// Make sure that calling an extern function pointer in an unreachable
// context doesn't cause an LLVM assertion
#[allow(unreachable_code)]
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test: issue had to do with "givens" in region inference,
+// which were not being considered during the contraction phase.
+
+// error-pattern:explicit panic
+
+struct Parser<'i: 't, 't>(&'i u8, &'t u8);
+
+impl<'i, 't> Parser<'i, 't> {
+ fn parse_nested_block<F, T>(&mut self, parse: F) -> Result<T, ()>
+ where for<'tt> F: FnOnce(&mut Parser<'i, 'tt>) -> T { panic!() }
+
+ fn expect_exhausted(&mut self) -> Result<(), ()> { Ok(()) }
+}
+
+fn main() {
+ let x = 0u8;
+ Parser(&x, &x).parse_nested_block(|input| input.expect_exhausted()).unwrap();
+}
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn value() -> u8 { 200 }
fn main() {
- let _x = value() + value() + value();
+ let _x = 200u8 + 200u8 + 200u8;
}
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
- let _x = 1_i32 << id(32);
+ let _x = 1_i32 << 32;
}
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
- let _x = 1 << id(-1);
+ let _x = 1 << -1;
}
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
- let _x = 1_u64 << id(64);
+ let _x = 1_u64 << 64;
}
// This function is checking that our automatic truncation does not
// sidestep the overflow checking.
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
// this signals overflow when checking is on
- let x = 1_i8 << id(17);
+ let x = 1_i8 << 17;
// ... but when checking is off, the fallback will truncate the
// input to its lower three bits (= 1). Note that this is *not*
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn value() -> u8 { 200 }
-
fn main() {
- let x = value() * 4;
+ let x = 200u8 * 4;
}
// error-pattern:thread '<main>' panicked at 'attempted to negate with overflow'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn value() -> i8 { std::i8::MIN }
-
fn main() {
- let _x = -value();
+ let _x = -std::i8::MIN;
}
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
- let _x = -1_i32 >> id(32);
+ let _x = -1_i32 >> 32;
}
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
- let _x = -1_i32 >> id(-1);
+ let _x = -1_i32 >> -1;
}
// error-pattern:thread '<main>' panicked at 'shift operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
- let _x = -1_i64 >> id(64);
+ let _x = -1_i64 >> 64;
}
// This function is checking that our (type-based) automatic
// truncation does not sidestep the overflow checking.
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
+#![warn(exceeding_bitshifts)]
fn main() {
// this signals overflow when checking is on
- let x = 2_i8 >> id(17);
+ let x = 2_i8 >> 17;
// ... but when checking is off, the fallback will truncate the
// input to its lower three bits (= 1). Note that this is *not*
// error-pattern:thread '<main>' panicked at 'arithmetic operation overflowed'
// compile-flags: -C debug-assertions
-// (Work around constant-evaluation)
-fn value() -> u8 { 42 }
-
fn main() {
- let _x = value() - (value() + 1);
+ let _x = 42u8 - (42u8 + 1);
}
all:
mkdir $(TMPDIR)/a
mkdir $(TMPDIR)/b
- $(CC) -c -o $(TMPDIR)/a/foo.o foo.c
- $(CC) -c -o $(TMPDIR)/b/foo.o bar.c
+ $(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c)
+ $(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c)
ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o
$(RUSTC) foo.rs
$(RUSTC) bar.rs
-include ../tools.mk
all:
- $(rustc) -o foo foo.rs
+ cp foo.rs $(TMPDIR)
+ cd $(TMPDIR) && $(RUSTC) -o foo foo.rs
+ $(call RUN,foo)
// ignore-license
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
int foo() { return 0; }
// ignore-license
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
int foo() { return 0; }
-include ../tools.mk
-HOST_LIB_DIR=$(TMPDIR)/../../../stage$(RUST_BUILD_STAGE)/lib
-
-all:
- $(RUSTC) foo.rs
- $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(call RPATH_LINK_SEARCH,$(HOST_LIB_DIR)) -Wl,-rpath,$(TMPDIR) $(EXTRACFLAGS)
+all: $(TMPDIR)/$(call BIN,bar)
$(call RUN,bar)
$(call REMOVE_DYLIBS,foo)
$(call FAIL,bar)
+
+ifdef IS_MSVC
+$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
+ $(CC) bar.c $(TMPDIR)/foo.lib $(call OUT_EXE,bar)
+else
+$(TMPDIR)/$(call BIN,bar): $(call DYLIB,foo)
+ $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) -L $(TMPDIR)
+endif
+
+$(call DYLIB,foo): foo.rs
+ $(RUSTC) foo.rs
-include ../tools.mk
-EXTRAFLAGS := $(EXTRACFLAGS)
-
# FIXME: ignore freebsd
ifneq ($(shell uname),FreeBSD)
all:
$(RUSTC) foo.rs
- $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRAFLAGS) $(EXTRACXXFLAGS)
+ cp $(TMPDIR)/libfoo.a $(call NATIVE_STATICLIB,foo2)
+ $(CC) bar.c $(call NATIVE_STATICLIB,foo2) $(call OUT_EXE,bar) \
+ $(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,bar)
rm $(call STATICLIB,foo*)
$(call RUN,bar)
-include ../tools.mk
-all: $(call STATICLIB,cfoo)
+all: $(call NATIVE_STATICLIB,cfoo)
$(RUSTC) foo.rs -C prefer-dynamic
$(RUSTC) bar.rs
- rm $(TMPDIR)/$(call STATICLIB_GLOB,cfoo)
+ rm $(call NATIVE_STATICLIB,cfoo)
$(call RUN,bar)
$(call REMOVE_DYLIBS,foo)
$(call FAIL,bar)
-include ../tools.mk
-all: $(call STATICLIB,cfoo)
+all: $(call NATIVE_STATICLIB,cfoo)
$(RUSTC) foo.rs
$(RUSTC) bar.rs
$(call REMOVE_RLIBS,foo)
- rm $(TMPDIR)/$(call STATICLIB_GLOB,cfoo)
+ rm $(call NATIVE_STATICLIB,cfoo)
$(call RUN,bar)
--- /dev/null
+-include ../tools.mk
+
+all:
+ echo 'fn main(){}' | $(RUSTC) -
+ $(call RUN,rust_out)
rm $(TMPDIR)/$(call BIN,bar)
$(RUSTC) foo1.rs
rm $(TMPDIR)/$(call BIN,foo)
- $(RUSTC) foo1.rs -o $(TMPDIR)/bar1
+ $(RUSTC) foo1.rs -o $(TMPDIR)/$(call BIN,bar1)
rm $(TMPDIR)/$(call BIN,bar1)
ifneq ($(shell uname),FreeBSD)
ifndef IS_WINDOWS
all:
- $(RUSTC) --emit dep-info,link --crate-type=lib lib.rs
+ cp *.rs $(TMPDIR)
+ $(RUSTC) --emit dep-info,link --crate-type=lib $(TMPDIR)/lib.rs
sleep 2
- touch foo.rs
+ touch $(TMPDIR)/foo.rs
-rm -f $(TMPDIR)/done
$(MAKE) -drf Makefile.foo
sleep 2
pwd
$(MAKE) -drf Makefile.foo
rm $(TMPDIR)/done && exit 1 || exit 0
+
+ # When a source file is deleted `make` should still work
+ rm $(TMPDIR)/bar.rs
+ cp $(TMPDIR)/lib2.rs $(TMPDIR)/lib.rs
+ $(MAKE) -drf Makefile.foo
else
all:
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+pub mod foo;
use rustc::session::config::{self, basic_options, build_configuration, Input, Options};
use rustc::session::build_session;
use rustc_driver::driver;
-use rustc_front::lowering::lower_crate;
+use rustc_front::lowering::{lower_crate, LoweringContext};
use rustc_resolve::MakeGlobMap;
use libc::c_void;
.expect("phase_2 returned `None`");
let krate = driver::assign_node_ids(&sess, krate);
- let mut hir_forest = ast_map::Forest::new(lower_crate(&krate));
+ let lcx = LoweringContext::new(&sess, Some(&krate));
+ let mut hir_forest = ast_map::Forest::new(lower_crate(&lcx, &krate));
let arenas = ty::CtxtArenas::new();
let ast_map = driver::make_map(&sess, &mut hir_forest);
driver::phase_3_run_analysis_passes(
- sess, ast_map, &krate, &arenas, id, MakeGlobMap::No, |tcx, analysis| {
+ &sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, analysis| {
let trans = driver::phase_4_translate_to_llvm(tcx, analysis);
let modp = llmod as usize;
(modp, deps)
- }).1
+ })
}).unwrap();
match handle.join() {
-include ../tools.mk
-all:
- $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
- $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
- $(RUSTC) testcrate.rs -L $(TMPDIR)
- $(RUSTC) test.rs -L $(TMPDIR)
+all: $(call NATIVE_STATICLIB,test)
+ $(RUSTC) testcrate.rs
+ $(RUSTC) test.rs
$(call RUN,test) || exit 1
-include ../tools.mk
-all:
- $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
- $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
- $(RUSTC) test.rs -L $(TMPDIR)
+all: $(call NATIVE_STATICLIB,test)
+ $(RUSTC) test.rs
$(call RUN,test) || exit 1
--- /dev/null
+-include ../tools.mk
+
+all: $(call NATIVE_STATICLIB,test)
+ $(RUSTC) test.rs
+ $(call RUN,test) || exit 1
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#include <assert.h>
+#include <stdint.h>
+
+struct Rect {
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t d;
+};
+
+struct BiggerRect {
+ struct Rect s;
+ int32_t a;
+ int32_t b;
+};
+
+struct FloatRect {
+ int32_t a;
+ int32_t b;
+ double c;
+};
+
+struct Huge {
+ int32_t a;
+ int32_t b;
+ int32_t c;
+ int32_t d;
+ int32_t e;
+};
+
+// System V x86_64 ABI:
+// a, b, c, d, e should be in registers
+// s should be byval pointer
+//
+// Win64 ABI:
+// a, b, c, d should be in registers
+// e should be on the stack
+// s should be byval pointer
+void byval_rect(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3);
+ assert(d == 4);
+ assert(e == 5);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 ABI:
+// a, b, c, d, e, f should be in registers
+// s should be byval pointer on the stack
+//
+// Win64 ABI:
+// a, b, c, d should be in registers
+// e, f should be on the stack
+// s should be byval pointer on the stack
+void byval_many_rect(int32_t a, int32_t b, int32_t c, int32_t d, int32_t e,
+ int32_t f, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3);
+ assert(d == 4);
+ assert(e == 5);
+ assert(f == 6);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 ABI:
+// a, b, c, d, e, f, g should be in sse registers
+// s should be split across 2 registers
+// t should be byval pointer
+//
+// Win64 ABI:
+// a, b, c, d should be in sse registers
+// e, f, g should be on the stack
+// s should be on the stack (treated as 2 i64's)
+// t should be on the stack (treated as an i64 and a double)
+void byval_rect_floats(float a, float b, double c, float d, float e,
+ float f, double g, struct Rect s, struct FloatRect t) {
+ assert(a == 1.);
+ assert(b == 2.);
+ assert(c == 3.);
+ assert(d == 4.);
+ assert(e == 5.);
+ assert(f == 6.);
+ assert(g == 7.);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+ assert(t.a == 3489);
+ assert(t.b == 3490);
+ assert(t.c == 8.);
+}
+
+// System V x86_64 ABI:
+// a, b, d, e, f should be in registers
+// c passed via sse registers
+// s should be byval pointer
+//
+// Win64 ABI:
+// a, b, d should be in registers
+// c passed via sse registers
+// e, f should be on the stack
+// s should be byval pointer
+void byval_rect_with_float(int32_t a, int32_t b, float c, int32_t d,
+ int32_t e, int32_t f, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3.);
+ assert(d == 4);
+ assert(e == 5);
+ assert(f == 6);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should be in registers
+// s should be split across 2 integer registers
+void split_rect(int32_t a, int32_t b, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should be in sse registers
+// s should be split across integer & sse registers
+void split_rect_floats(float a, float b, struct FloatRect s) {
+ assert(a == 1.);
+ assert(b == 2.);
+ assert(s.a == 3489);
+ assert(s.b == 3490);
+ assert(s.c == 8.);
+}
+
+// System V x86_64 ABI:
+// a, b, d, f should be in registers
+// c, e passed via sse registers
+// s should be split across 2 registers
+//
+// Win64 ABI:
+// a, b, d should be in registers
+// c passed via sse registers
+// e, f should be on the stack
+// s should be on the stack (treated as 2 i64's)
+void split_rect_with_floats(int32_t a, int32_t b, float c,
+ int32_t d, float e, int32_t f, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3.);
+ assert(d == 4);
+ assert(e == 5.);
+ assert(f == 6);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b, c should be in registers
+// s should be split across 2 registers
+// t should be a byval pointer
+void split_and_byval_rect(int32_t a, int32_t b, int32_t c, struct Rect s, struct Rect t) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+ assert(t.a == 553);
+ assert(t.b == 554);
+ assert(t.c == 555);
+ assert(t.d == 556);
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should in registers
+// s and return should be split across 2 registers
+struct Rect split_ret_byval_struct(int32_t a, int32_t b, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+ return s;
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b, c, d should be in registers
+// return should be in a hidden sret pointer
+// s should be a byval pointer
+struct BiggerRect sret_byval_struct(int32_t a, int32_t b, int32_t c, int32_t d, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(c == 3);
+ assert(d == 4);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+
+ struct BiggerRect t;
+ t.s = s; t.a = 27834; t.b = 7657;
+ return t;
+}
+
+// System V x86_64 & Win64 ABI:
+// a, b should be in registers
+// return should be in a hidden sret pointer
+// s should be split across 2 registers
+struct BiggerRect sret_split_struct(int32_t a, int32_t b, struct Rect s) {
+ assert(a == 1);
+ assert(b == 2);
+ assert(s.a == 553);
+ assert(s.b == 554);
+ assert(s.c == 555);
+ assert(s.d == 556);
+
+ struct BiggerRect t;
+ t.s = s; t.a = 27834; t.b = 7657;
+ return t;
+}
+
+// System V x86_64 & Win64 ABI:
+// s should be byval pointer (since sizeof(s) > 16)
+// return should in a hidden sret pointer
+struct Huge huge_struct(struct Huge s) {
+ assert(s.a == 5647);
+ assert(s.b == 5648);
+ assert(s.c == 5649);
+ assert(s.d == 5650);
+ assert(s.e == 5651);
+
+ return s;
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Passing structs via FFI should work regardless of whether
+// they get passed in multiple registers, byval pointers or the stack
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct Rect {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct BiggerRect {
+ s: Rect,
+ a: i32,
+ b: i32
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct FloatRect {
+ a: i32,
+ b: i32,
+ c: f64
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct Huge {
+ a: i32,
+ b: i32,
+ c: i32,
+ d: i32,
+ e: i32
+}
+
+#[link(name = "test", kind = "static")]
+extern {
+ fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);
+
+ fn byval_many_rect(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, s: Rect);
+
+ fn byval_rect_floats(a: f32, b: f32, c: f64, d: f32, e: f32,
+ f: f32, g: f64, s: Rect, t: FloatRect);
+
+ fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);
+
+ fn split_rect(a: i32, b: i32, s: Rect);
+
+ fn split_rect_floats(a: f32, b: f32, s: FloatRect);
+
+ fn split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect);
+
+ fn split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect);
+
+ fn split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect;
+
+ fn sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect;
+
+ fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;
+
+ fn huge_struct(s: Huge) -> Huge;
+}
+
+fn main() {
+ let s = Rect { a: 553, b: 554, c: 555, d: 556 };
+ let t = BiggerRect { s: s, a: 27834, b: 7657 };
+ let u = FloatRect { a: 3489, b: 3490, c: 8. };
+ let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
+
+ unsafe {
+ byval_rect(1, 2, 3, 4, 5, s);
+ byval_many_rect(1, 2, 3, 4, 5, 6, s);
+ byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
+ byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
+ split_rect(1, 2, s);
+ split_rect_floats(1., 2., u);
+ split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
+ split_and_byval_rect(1, 2, 3, s, s);
+ split_rect(1, 2, s);
+ assert_eq!(huge_struct(v), v);
+ assert_eq!(split_ret_byval_struct(1, 2, s), s);
+ assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
+ assert_eq!(sret_split_struct(1, 2, s), t);
+ }
+}
-include ../tools.mk
-all:
- $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
- $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
- $(RUSTC) test.rs -L $(TMPDIR)
+all: $(call NATIVE_STATICLIB,test)
+ $(RUSTC) test.rs
$(call RUN,test) || exit 1
// ignore-license
// Pragma needed cause of gcc bug on windows: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991
+
+#ifdef _MSC_VER
+#pragma pack(push,1)
+struct Foo {
+ char a;
+ short b;
+ char c;
+};
+#else
#pragma pack(1)
struct __attribute__((packed)) Foo {
char a;
short b;
char c;
};
+#endif
struct Foo foo(struct Foo foo) {
return foo;
-include ../tools.mk
-all:
- $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
- $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
- $(RUSTC) testcrate.rs -L $(TMPDIR)
- $(RUSTC) test.rs -L $(TMPDIR)
+all: $(call NATIVE_STATICLIB,test)
+ $(RUSTC) testcrate.rs
+ $(RUSTC) test.rs
$(call RUN,test) || exit 1
# correct to complete the linkage. If passed as "-lfoo -lbar", then the 'foo'
# library will be stripped out, and the linkage will fail.
-all: $(call STATICLIB,foo) $(call STATICLIB,bar)
+all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar)
$(RUSTC) foo.rs
$(RUSTC) bar.rs
$(RUSTC) main.rs -Z print-link-args
--- /dev/null
+-include ../tools.mk
+
+all:
+ touch $(TMPDIR)/libfoo.a
+ echo | $(RUSTC) - --crate-type=rlib -lstatic=foo 2>&1 | grep "failed to add native library"
+++ /dev/null
--include ../tools.mk
-
-all: $(call STATICLIB,foo)
- $(RUSTC) foo.rs
- $(RUSTC) bar.rs
- $(call RUN,bar)
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-extern crate foo;
-
-#[link(name = "foo")]
-extern {}
-
-fn main() {
- foo::foo();
-}
+++ /dev/null
-// ignore-license
-void some_c_symbol() {}
+++ /dev/null
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-#![crate_type = "rlib"]
-
-extern {
- fn some_c_symbol();
-}
-
-pub fn foo() {
- unsafe { some_c_symbol() }
-}
all:
$(RUSTC) foo.rs --crate-type=rlib
$(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a
- $(CC) foo.c -lbar -o $(call RUN_BINFILE,foo) $(EXTRACFLAGS)
+ $(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo)
$(call RUN,foo)
--- /dev/null
+-include ../tools.mk
+
+all:
+ TMP=fake TMPDIR=fake $(RUSTC) foo.rs 2>&1 | grep "couldn't create a temp dir:"
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {}
-include ../tools.mk
-all: $(TMPDIR)/libfoo.a
+all: $(call NATIVE_STATICLIB,foo)
$(RUSTC) foo.rs -C extra-filename=-383hf8 -C prefer-dynamic
$(RUSTC) bar.rs
$(call RUN,bar)
// ignore-license
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
void foo() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(linked_from)]
#![crate_type = "dylib"]
#[link(name = "foo", kind = "static")]
+#[linked_from = "foo"]
extern {
pub fn foo();
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(rustc_private, path, convert)]
+#![feature(rustc_private)]
extern crate rustc;
extern crate rustc_driver;
extern crate syntax;
use rustc::session::{build_session, Session};
-use rustc::session::config::{basic_options, build_configuration, Input, OutputTypeExe};
+use rustc::session::config::{basic_options, build_configuration, Input, OutputType};
use rustc_driver::driver::{compile_input, CompileController};
use syntax::diagnostics::registry::Registry;
fn basic_sess(sysroot: PathBuf) -> Session {
let mut opts = basic_options();
- opts.output_types = vec![OutputTypeExe];
+ opts.output_types.insert(OutputType::Exe, None);
opts.maybe_sysroot = Some(sysroot);
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
-include ../tools.mk
-all:
- $(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
- $(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
- $(RUSTC) test.rs -L $(TMPDIR)
+all: $(call NATIVE_STATICLIB,test)
+ $(RUSTC) test.rs
$(call RUN,test) || exit 1
all:
$(RUSTC) -o "" blank.rs 2>&1 | \
- grep 'No such file or directory'
+ grep -i 'No such file or directory'
--- /dev/null
+-include ../tools.mk
+
+all: $(call NATIVE_STATICLIB,a) $(call NATIVE_STATICLIB,b)
+ $(RUSTC) a.rs
+ $(RUSTC) b.rs
+ $(call RUN,b)
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+void a(void) {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "rlib"]
+
+#[link(name = "a", kind = "static")]
+extern {
+ pub fn a();
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern void a(void);
+
+void b(void) {
+ a();
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate a;
+
+#[link(name = "b", kind = "static")]
+extern {
+ pub fn b();
+}
+
+
+fn main() {
+ unsafe { b(); }
+}
CORRECT_DIR=$(TMPDIR)/correct
WRONG_DIR=$(TMPDIR)/wrong
-all: $(TMPDIR)/libcorrect.a $(TMPDIR)/libwrong.a
+F := $(call NATIVE_STATICLIB_FILE,foo)
+
+all: $(call NATIVE_STATICLIB,correct) $(call NATIVE_STATICLIB,wrong)
mkdir -p $(CORRECT_DIR) $(WRONG_DIR)
- mv $(TMPDIR)/libcorrect.a $(CORRECT_DIR)/libfoo.a
- mv $(TMPDIR)/libwrong.a $(WRONG_DIR)/libfoo.a
+ mv $(call NATIVE_STATICLIB,correct) $(CORRECT_DIR)/$(F)
+ mv $(call NATIVE_STATICLIB,wrong) $(WRONG_DIR)/$(F)
$(RUSTC) main.rs -o $(TMPDIR)/should_succeed -L $(CORRECT_DIR) -L $(WRONG_DIR)
$(call RUN,should_succeed)
$(RUSTC) main.rs -o $(TMPDIR)/should_fail -L $(WRONG_DIR) -L $(CORRECT_DIR)
-include ../tools.mk
-all:
- $(CC) foo.c -c -o $(TMPDIR)/foo.o
- $(AR) rcs $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o
- $(RUSTC) bar.rs -lfoo -L $(TMPDIR)
+all: $(call NATIVE_STATICLIB,foo)
+ $(RUSTC) bar.rs
$(call RUN,bar) || exit 1
#[linkage = "external"]
static BAZ: i32 = 21;
+#[link(name = "foo", kind = "static")]
extern {
fn what() -> i32;
}
--- /dev/null
+-include ../tools.mk
+
+# Make sure we don't ICE if the linker prints a non-UTF-8 error message.
+
+ifdef IS_WINDOWS
+# ignore windows
+
+# This does not work in its current form on windows, possibly due to
+# gcc bugs or something about valid Windows paths. See issue #29151
+# for more information.
+all:
+
+else
+
+# The zzz it to allow humans to tab complete or glob this thing.
+bad_dir := $(TMPDIR)/zzz$$'\xff'
+
+all:
+ $(RUSTC) library.rs
+ mkdir $(bad_dir)
+ mv $(TMPDIR)/liblibrary.a $(bad_dir)
+ LIBRARY_PATH=$(bad_dir) $(RUSTC) exec.rs 2>&1 | grep this_symbol_not_defined
+
+endif
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[link(name="library")]
+extern "C" {
+ fn foo();
+}
+
+fn main() { unsafe { foo(); } }
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "staticlib"]
+
+extern "C" {
+ fn this_symbol_not_defined();
+}
+
+#[no_mangle]
+pub extern "C" fn foo() {
+ unsafe { this_symbol_not_defined(); }
+}
all:
$(RUSTC) foo.rs -C lto
- $(CC) bar.c -lfoo -o $(call RUN_BINFILE,bar) $(EXTRACFLAGS) $(EXTRACXXFLAGS)
+ $(CC) bar.c $(TMPDIR)/libfoo.a \
+ $(call OUT_EXE,bar) \
+ $(EXTRACFLAGS) $(EXTRACXXFLAGS)
$(call RUN,bar)
-include ../tools.mk
+ifdef IS_MSVC
+# FIXME(#27979)
+all:
+else
all:
$(RUSTC) foo.rs
$(RUSTC) bar.rs
$(RUSTC) main.rs
$(call RUN,main)
+endif
+++ /dev/null
-// ignore-license
-extern void foo();
-
-void bar() { foo(); }
+++ /dev/null
-// ignore-license
-void foo() {}
$(RUSTC) foo.rs --crate-type=rlib,dylib,staticlib
$(call REMOVE_RLIBS,bar)
$(call REMOVE_DYLIBS,bar)
- rm $(TMPDIR)/$(call STATICLIB_GLOB,bar)
+ rm $(TMPDIR)/libbar.a
+ rm -f $(TMPDIR)/bar.{exp,lib,pdb}
# Check that $(TMPDIR) is empty.
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
$(RUSTC) foo.rs --crate-type=bin
rm $(TMPDIR)/$(call BIN,bar)
+ rm -f $(TMPDIR)/bar.pdb
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
$(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link
rm $(TMPDIR)/bar.s
rm $(TMPDIR)/bar.o
rm $(TMPDIR)/$(call BIN,bar)
+ rm -f $(TMPDIR)/bar.pdb
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=asm -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit asm -o $(TMPDIR)/foo
+ rm $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit asm=$(TMPDIR)/foo
rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=llvm-bc -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit llvm-bc -o $(TMPDIR)/foo
+ rm $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit llvm-bc=$(TMPDIR)/foo
rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=llvm-ir -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit llvm-ir -o $(TMPDIR)/foo
+ rm $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/foo
rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=obj -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit obj -o $(TMPDIR)/foo
+ rm $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit obj=$(TMPDIR)/foo
rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --emit=link -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --emit link -o $(TMPDIR)/$(call BIN,foo)
rm $(TMPDIR)/$(call BIN,foo)
+ $(RUSTC) foo.rs --emit link=$(TMPDIR)/$(call BIN,foo)
+ rm $(TMPDIR)/$(call BIN,foo)
+ rm -f $(TMPDIR)/foo.pdb
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
$(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo
rm $(TMPDIR)/foo
+ $(RUSTC) foo.rs --crate-type=rlib --emit link=$(TMPDIR)/foo
+ rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/foo
- rm $(TMPDIR)/$(call BIN,foo) # FIXME 13794
+ $(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/$(call BIN,foo)
+ rm $(TMPDIR)/$(call BIN,foo)
+ $(RUSTC) foo.rs --crate-type=dylib --emit link=$(TMPDIR)/$(call BIN,foo)
+ rm $(TMPDIR)/$(call BIN,foo)
+ rm -f $(TMPDIR)/foo.{exp,lib,pdb}
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
$(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo
rm $(TMPDIR)/foo
+ $(RUSTC) foo.rs --crate-type=staticlib --emit link=$(TMPDIR)/foo
+ rm $(TMPDIR)/foo
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
- $(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/foo
+ $(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/$(call BIN,foo)
rm $(TMPDIR)/$(call BIN,foo)
+ $(RUSTC) foo.rs --crate-type=bin --emit link=$(TMPDIR)/$(call BIN,foo)
+ rm $(TMPDIR)/$(call BIN,foo)
+ rm -f $(TMPDIR)/foo.pdb
+ [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
+
+ $(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/ir \
+ --emit link \
+ --crate-type=rlib
+ rm $(TMPDIR)/ir
+ rm $(TMPDIR)/libbar.rlib
+ [ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
+
+ $(RUSTC) foo.rs --emit asm=$(TMPDIR)/asm \
+ --emit llvm-ir=$(TMPDIR)/ir \
+ --emit llvm-bc=$(TMPDIR)/bc \
+ --emit obj=$(TMPDIR)/obj \
+ --emit link=$(TMPDIR)/link \
+ --crate-type=staticlib
+ rm $(TMPDIR)/asm
+ rm $(TMPDIR)/ir
+ rm $(TMPDIR)/bc
+ rm $(TMPDIR)/obj
+ rm $(TMPDIR)/link
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
$(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link --crate-type=staticlib
rm $(TMPDIR)/bar.ll
rm $(TMPDIR)/bar.s
rm $(TMPDIR)/bar.o
- rm $(TMPDIR)/$(call STATICLIB_GLOB,bar)
+ rm $(TMPDIR)/libbar.a
mv $(TMPDIR)/bar.bc $(TMPDIR)/foo.bc
# Don't check that the $(TMPDIR) is empty - we left `foo.bc` for later
# comparison.
-include ../tools.mk
-all:
+all: others
$(RUSTC) -C relocation-model=dynamic-no-pic foo.rs
$(call RUN,foo)
$(RUSTC) -C relocation-model=default foo.rs
$(call RUN,foo)
+ $(RUSTC) -C relocation-model=default --crate-type=dylib foo.rs
+ $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs
+
+ifdef IS_MSVC
+# FIXME(#28026)
+others:
+else
+others:
$(RUSTC) -C relocation-model=static foo.rs
$(call RUN,foo)
-
- $(RUSTC) -C relocation-model=default --crate-type=dylib foo.rs
$(RUSTC) -C relocation-model=static --crate-type=dylib foo.rs
- $(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs
+endif
-include ../tools.mk
all: code
krate2: krate2.rs
- $(RUSTC) $<
+ $(RUSTC) $<
code: foo.rs krate2
$(RUSTC) foo.rs -Zsave-analysis
if let SomeEnum::Strings(..) = s7 {
println!("hello!");
}
+
+ for i in 0..5 {
+ foo_foo(i);
+ }
+
+ if let Some(x) = None {
+ foo_foo(x);
+ }
+
+ if false {
+ } else if let Some(y) = None {
+ foo_foo(y);
+ }
+
+ while let Some(z) = None {
+ foo_foo(z);
+ }
}
+fn foo_foo(_: i32) {}
+
impl Iterator for nofields {
type Item = (usize, usize);
-include ../tools.mk
+TO_LINK := $(call DYLIB,bar)
+ifdef IS_MSVC
+LINK_ARG = $(TO_LINK:dll=lib)
+else
+LINK_ARG = $(TO_LINK)
+endif
+
all:
$(RUSTC) foo.rs
$(RUSTC) bar.rs
- $(CC) main.c -o $(call RUN_BINFILE,main) -lbar $(EXTRACFLAGS)
+ $(CC) main.c $(call OUT_EXE,main) $(LINK_ARG) $(EXTRACFLAGS)
rm $(TMPDIR)/*.rlib
rm $(call DYLIB,foo)
$(call RUN,main)
BARE_RUSTC := $(HOST_RPATH_ENV) $(RUSTC)
RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR)
-CC := $(CC) -L $(TMPDIR)
+#CC := $(CC) -L $(TMPDIR)
HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py
# This is the name of the binary we will generate and run; use this
# variable before running the binary.
RLIB_GLOB = lib$(1)*.rlib
-STATICLIB = $(TMPDIR)/lib$(1).a
-STATICLIB_GLOB = lib$(1)*.a
BIN = $(1)
UNAME = $(shell uname)
FAIL = $(TARGET_RPATH_ENV) $(RUN_BINFILE) && exit 1 || exit 0
DYLIB_GLOB = lib$(1)*.dylib
DYLIB = $(TMPDIR)/lib$(1).dylib
-RPATH_LINK_SEARCH =
+STATICLIB = $(TMPDIR)/lib$(1).a
+STATICLIB_GLOB = lib$(1)*.a
else
ifdef IS_WINDOWS
RUN = PATH="$(PATH):$(TARGET_RPATH_DIR)" $(RUN_BINFILE)
FAIL = PATH="$(PATH):$(TARGET_RPATH_DIR)" $(RUN_BINFILE) && exit 1 || exit 0
DYLIB_GLOB = $(1)*.dll
DYLIB = $(TMPDIR)/$(1).dll
+STATICLIB = $(TMPDIR)/$(1).lib
+STATICLIB_GLOB = $(1)*.lib
BIN = $(1).exe
-RPATH_LINK_SEARCH =
else
RUN = $(TARGET_RPATH_ENV) $(RUN_BINFILE)
FAIL = $(TARGET_RPATH_ENV) $(RUN_BINFILE) && exit 1 || exit 0
DYLIB_GLOB = lib$(1)*.so
DYLIB = $(TMPDIR)/lib$(1).so
-RPATH_LINK_SEARCH = -Wl,-rpath-link=$(1)
+STATICLIB = $(TMPDIR)/lib$(1).a
+STATICLIB_GLOB = lib$(1)*.a
+endif
endif
+
+ifdef IS_MSVC
+COMPILE_OBJ = $(CC) -c -Fo:`cygpath -w $(1)` $(2)
+NATIVE_STATICLIB_FILE = $(1).lib
+NATIVE_STATICLIB = $(TMPDIR)/$(call NATIVE_STATICLIB_FILE,$(1))
+OUT_EXE=-Fe:`cygpath -w $(TMPDIR)/$(call BIN,$(1))` \
+ -Fo:`cygpath -w $(TMPDIR)/$(1).obj`
+else
+COMPILE_OBJ = $(CC) -c -o $(1) $(2)
+NATIVE_STATICLIB_FILE = lib$(1).a
+NATIVE_STATICLIB = $(call STATICLIB,$(1))
+OUT_EXE=-o $(TMPDIR)/$(1)
endif
+
# Extra flags needed to compile a working executable with the standard library
ifdef IS_WINDOWS
+ifdef IS_MSVC
+ EXTRACFLAGS := ws2_32.lib userenv.lib shell32.lib advapi32.lib
+else
EXTRACFLAGS := -lws2_32 -luserenv
+endif
else
ifeq ($(UNAME),Darwin)
else
else
ifeq ($(UNAME),OpenBSD)
EXTRACFLAGS := -lm -lpthread
+ # extend search lib for found estdc++ if build using gcc from
+ # ports under OpenBSD. This is needed for:
+ # - run-make/execution-engine
+ # - run-make/issue-19371
+ RUSTC := $(RUSTC) -L/usr/local/lib
else
EXTRACFLAGS := -lm -lrt -ldl -lpthread
EXTRACXXFLAGS := -lstdc++
%.a: %.o
ar crus $@ $<
+%.lib: lib%.o
+ ar crus $@ $<
%.dylib: %.o
$(CC) -dynamiclib -Wl,-dylib -o $@ $<
%.so: %.o
$(CC) -o $@ $< -shared
+
+ifdef IS_MSVC
+%.dll: lib%.o
+ $(CC) $< -link -dll -out:`cygpath -w $@`
+else
%.dll: lib%.o
$(CC) -o $@ $< -shared
+endif
$(TMPDIR)/lib%.o: %.c
- $(CC) -c -o $@ $<
+ $(call COMPILE_OBJ,$@,$<)
// ignore-cross-compile
-#![feature(rustc_private, path_ext)]
+#![feature(rustc_private)]
extern crate rustc_back;
use std::ffi::CString;
-use std::fs::{self, File, PathExt};
+use std::fs::{self, File};
use rustc_back::tempdir::TempDir;
fn rename_directory() {
use std::cell::Cell;
-#[derive(Show)]
+#[derive(Debug)]
struct B<'a> {
a: [Cell<Option<&'a B<'a>>>; 2]
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(augmented_assignments)]
+#![feature(op_assign_traits)]
+
+use std::mem;
+use std::ops::{
+ AddAssign, BitAndAssign, BitOrAssign, BitXorAssign, DivAssign, Index, MulAssign, RemAssign,
+ ShlAssign, ShrAssign, SubAssign,
+};
+
+#[derive(Debug, PartialEq)]
+struct Int(i32);
+
+struct Slice([i32]);
+
+impl Slice {
+ fn new(slice: &mut [i32]) -> &mut Slice {
+ unsafe {
+ mem::transmute(slice)
+ }
+ }
+}
+
+fn main() {
+ let mut x = Int(1);
+
+ x += Int(2);
+ assert_eq!(x, Int(0b11));
+
+ x &= Int(0b01);
+ assert_eq!(x, Int(0b01));
+
+ x |= Int(0b10);
+ assert_eq!(x, Int(0b11));
+
+ x ^= Int(0b01);
+ assert_eq!(x, Int(0b10));
+
+ x /= Int(2);
+ assert_eq!(x, Int(1));
+
+ x *= Int(3);
+ assert_eq!(x, Int(3));
+
+ x %= Int(2);
+ assert_eq!(x, Int(1));
+
+ // overloaded RHS
+ x <<= 1u8;
+ assert_eq!(x, Int(2));
+
+ x <<= 1u16;
+ assert_eq!(x, Int(4));
+
+ x >>= 1u8;
+ assert_eq!(x, Int(2));
+
+ x >>= 1u16;
+ assert_eq!(x, Int(1));
+
+ x -= Int(1);
+ assert_eq!(x, Int(0));
+
+ // indexed LHS
+ let mut v = vec![Int(1), Int(2)];
+ v[0] += Int(2);
+ assert_eq!(v[0], Int(3));
+
+ // unsized RHS
+ let mut array = [0, 1, 2];
+ *Slice::new(&mut array) += 1;
+ assert_eq!(array[0], 1);
+ assert_eq!(array[1], 2);
+ assert_eq!(array[2], 3);
+}
+
+impl AddAssign for Int {
+ fn add_assign(&mut self, rhs: Int) {
+ self.0 += rhs.0;
+ }
+}
+
+impl BitAndAssign for Int {
+ fn bitand_assign(&mut self, rhs: Int) {
+ self.0 &= rhs.0;
+ }
+}
+
+impl BitOrAssign for Int {
+ fn bitor_assign(&mut self, rhs: Int) {
+ self.0 |= rhs.0;
+ }
+}
+
+impl BitXorAssign for Int {
+ fn bitxor_assign(&mut self, rhs: Int) {
+ self.0 ^= rhs.0;
+ }
+}
+
+impl DivAssign for Int {
+ fn div_assign(&mut self, rhs: Int) {
+ self.0 /= rhs.0;
+ }
+}
+
+impl MulAssign for Int {
+ fn mul_assign(&mut self, rhs: Int) {
+ self.0 *= rhs.0;
+ }
+}
+
+impl RemAssign for Int {
+ fn rem_assign(&mut self, rhs: Int) {
+ self.0 %= rhs.0;
+ }
+}
+
+impl ShlAssign<u8> for Int {
+ fn shl_assign(&mut self, rhs: u8) {
+ self.0 <<= rhs;
+ }
+}
+
+impl ShlAssign<u16> for Int {
+ fn shl_assign(&mut self, rhs: u16) {
+ self.0 <<= rhs;
+ }
+}
+
+impl ShrAssign<u8> for Int {
+ fn shr_assign(&mut self, rhs: u8) {
+ self.0 >>= rhs;
+ }
+}
+
+impl ShrAssign<u16> for Int {
+ fn shr_assign(&mut self, rhs: u16) {
+ self.0 >>= rhs;
+ }
+}
+
+impl SubAssign for Int {
+ fn sub_assign(&mut self, rhs: Int) {
+ self.0 -= rhs.0;
+ }
+}
+
+impl AddAssign<i32> for Slice {
+ fn add_assign(&mut self, rhs: i32) {
+ for lhs in &mut self.0 {
+ *lhs += rhs;
+ }
+ }
+}
}
pub fn main() {
- let x: Box<_> = box() (box 3usize as Box<double>);
+ let x: Box<_> = box (box 3usize as Box<double>);
assert_eq!(x.double(), 6);
}
assert_eq!(v, 22);
let v = Counter::new(22).inc().inc().get();
- assert_eq!(v, 24);;
+ assert_eq!(v, 24);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(cfg_target_vendor)]
+
+#[cfg(target_vendor = "unknown")]
+pub fn main() {
+}
+
+#[cfg(not(target_vendor = "unknown"))]
+pub fn main() {
+}
use std::mem;
-#[derive(PartialEq, Show)]
+#[derive(PartialEq, Debug)]
enum Foo {
A(u32),
Bar([u16; 4]),
--- /dev/null
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+
+const fn add(x: usize, y: usize) -> usize {
+ x + y
+}
+
+const ARR: [i32; add(1, 2)] = [5, 6, 7];
+
+pub fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A quick test of 'unsafe const fn' functionality
+
+#![feature(const_fn)]
+
+const unsafe fn dummy(v: u32) -> u32 {
+ !v
+}
+
+struct Type;
+impl Type {
+ const unsafe fn new() -> Type {
+ Type
+ }
+}
+
+const VAL: u32 = unsafe { dummy(0xFFFF) };
+const TYPE_INST: Type = unsafe { Type::new() };
+
+fn main() {
+ assert_eq!(VAL, 0xFFFF0000);
+}
($e:expr) => (match $e { Ok(e) => e, Err(e) => panic!("error: {}", e) })
}
+#[test]
fn test_destroy_once() {
let mut p = sleeper();
- match p.kill() {
- Ok(()) => {}
- Err(e) => panic!("error: {}", e),
- }
+ t!(p.kill());
}
#[cfg(unix)]
pub fn sleeper() -> Child {
- Command::new("sleep").arg("1000").spawn().unwrap()
+ t!(Command::new("sleep").arg("1000").spawn())
}
#[cfg(windows)]
pub fn sleeper() -> Child {
// There's a `timeout` command on windows, but it doesn't like having
// its output piped, so instead just ping ourselves a few times with
// gaps in between so we're sure this process is alive for awhile
- Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn().unwrap()
+ t!(Command::new("ping").arg("127.0.0.1").arg("-n").arg("1000").spawn())
}
+#[test]
fn test_destroy_twice() {
let mut p = sleeper();
t!(p.kill()); // this shouldn't crash...
#[test]
fn test_destroy_actually_kills() {
- #[cfg(all(unix,not(target_os="android")))]
- static BLOCK_COMMAND: &'static str = "cat";
-
- #[cfg(all(unix,target_os="android"))]
- static BLOCK_COMMAND: &'static str = "/system/bin/cat";
-
- #[cfg(windows)]
- static BLOCK_COMMAND: &'static str = "cmd";
+ let cmd = if cfg!(windows) {
+ "cmd"
+ } else if cfg!(target_os = "android") {
+ "/system/bin/cat"
+ } else {
+ "cat"
+ };
// this process will stay alive indefinitely trying to read from stdin
- let mut p = Command::new(BLOCK_COMMAND)
- .stdin(Stdio::piped())
- .spawn().unwrap();
+ let mut p = t!(Command::new(cmd)
+ .stdin(Stdio::piped())
+ .spawn());
- p.kill().unwrap();
+ t!(p.kill());
// Don't let this test time out, this should be quick
let (tx, rx) = channel();
process::exit(1);
}
});
- let code = p.wait().unwrap().code();
+ let code = t!(p.wait()).code();
if cfg!(windows) {
assert!(code.is_some());
} else {
pub fn main() {
use crate_method_reexport_grrrrrrr2::rust::add;
use crate_method_reexport_grrrrrrr2::rust::cx;
- let x: Box<_> = box () ();
+ let x: Box<_> = box ();
x.cx();
let y = ();
y.add("hi".to_string());
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#[derive(Show)]
-//~^ WARNING derive(Show) is deprecated
+#![feature(rustc_private)]
+
+extern crate serialize;
+
+#[derive(Encodable)]
+//~^ WARNING derive(Encodable) is deprecated in favor of derive(RustcEncodable)
struct Test1;
fn main() { }
// through the collection, for every collection type that supports
// this.
-#![feature(vecmap)]
+// HIGH LEVEL DESCRIPTION OF THE TEST ARCHITECTURE
+// -----------------------------------------------
+//
+// We pick a data structure and want to make a cyclic construction
+// from it. Each test of interest is labelled starting with "Cycle N:
+// { ... }" where N is the test number and the "..."`is filled in with
+// a graphviz-style description of the graph structure that the
+// author believes is being made. So "{ a -> b, b -> (c,d), (c,d) -> e }"
+// describes a line connected to a diamond:
+//
+// c
+// / \
+// a - b e
+// \ /
+// d
+//
+// (Note that the above directed graph is actually acyclic.)
+//
+// The different graph structures are often composed of different data
+// types. Some may be built atop `Vec`, others atop `HashMap`, etc.
+//
+// For each graph structure, we actually *confirm* that a cycle exists
+// (as a safe-guard against a test author accidentally leaving it out)
+// by traversing each graph and "proving" that a cycle exists within it.
+//
+// To do this, while trying to keep the code uniform (despite working
+// with different underlying collection and smart-pointer types), we
+// have a standard traversal API:
+//
+// 1. every node in the graph carries a `mark` (a u32, init'ed to 0).
+//
+// 2. every node provides a method to visit its children
+//
+// 3. a traversal attmepts to visit the nodes of the graph and prove that
+// it sees the same node twice. It does this by setting the mark of each
+// node to a fresh non-zero value, and if it sees the current mark, it
+// "knows" that it must have found a cycle, and stops attempting further
+// traversal.
+//
+// 4. each traversal is controlled by a bit-string that tells it which child
+// it visit when it can take different paths. As a simple example,
+// in a binary tree, 0 could mean "left" (and 1, "right"), so that
+// "00010" means "left, left, left, right, left". (In general it will
+// read as many bits as it needs to choose one child.)
+//
+// The graphs in this test are all meant to be very small, and thus
+// short bitstrings of less than 64 bits should always suffice.
+//
+// (An earlier version of this test infrastructure simply had any
+// given traversal visit all children it encountered, in a
+// depth-first manner; one problem with this approach is that an
+// acyclic graph can still have sharing, which would then be treated
+// as a repeat mark and reported as a detected cycle.)
+//
+// The travseral code is a little more complicated because it has been
+// programmed in a somewhat defensive manner. For example it also has
+// a max threshold for the number of nodes it will visit, to guard
+// against scenarios where the nodes are not correctly setting their
+// mark when asked. There are various other methods not discussed here
+// that are for aiding debugging the test when it runs, such as the
+// `name` method that all nodes provide.
+//
+// So each test:
+//
+// 1. allocates the nodes in the graph,
+//
+// 2. sets up the links in the graph,
+//
+// 3. clones the "ContextData"
+//
+// 4. chooses a new current mark value for this test
+//
+// 5. initiates a traversal, potentially from multiple starting points
+// (aka "roots"), with a given control-string (potentially a
+// different string for each root). if it does start from a
+// distinct root, then such a test should also increment the
+// current mark value, so that this traversal is considered
+// distinct from the prior one on this graph structure.
+//
+// Note that most of the tests work with the default control string
+// of all-zeroes.
+//
+// 6. assert that the context confirms that it actually saw a cycle (since a traversal
+// might have terminated, e.g. on a tree structure that contained no cycles).
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
use std::cmp::Ordering;
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::collections::btree_map::BTreeMap;
use std::collections::btree_set::BTreeSet;
use std::hash::{Hash, Hasher};
+use std::rc::Rc;
+use std::sync::{Arc, RwLock, Mutex};
const PRINT: bool = false;
skipped: 0,
curr_mark: 0,
saw_prev_marked: false,
+ control_bits: 0,
};
+ // SANITY CHECK FOR TEST SUITE (thus unnumbered)
+ // Not a cycle: { v[0] -> (v[1], v[2]), v[1] -> v[3], v[2] -> v[3] };
+ let v: Vec<S2> = vec![Named::new("s0"),
+ Named::new("s1"),
+ Named::new("s2"),
+ Named::new("s3")];
+ v[0].next.set((Some(&v[1]), Some(&v[2])));
+ v[1].next.set((Some(&v[3]), None));
+ v[2].next.set((Some(&v[3]), None));
+ v[3].next.set((None, None));
+
+ let mut c = c_orig.clone();
+ c.curr_mark = 10;
+ assert!(!c.saw_prev_marked);
+ v[0].descend_into_self(&mut c);
+ assert!(!c.saw_prev_marked); // <-- different from below, b/c acyclic above
+
+ if PRINT { println!(""); }
+
// Cycle 1: { v[0] -> v[1], v[1] -> v[0] };
// does not exercise `v` itself
let v: Vec<S> = vec![Named::new("s0"),
let mut c = c_orig.clone();
c.curr_mark = 10;
assert!(!c.saw_prev_marked);
- v[0].for_each_child(&mut c);
+ v[0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
let mut c = c_orig.clone();
c.curr_mark = 20;
assert!(!c.saw_prev_marked);
- v.for_each_child(&mut c);
+ v.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
for (key, _) in h.iter() {
c.curr_mark += 1;
c.saw_prev_marked = false;
- key.for_each_child(&mut c);
+ key.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
}
for (key, _) in h.iter() {
c.curr_mark += 1;
c.saw_prev_marked = false;
- key.for_each_child(&mut c);
+ key.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
// break;
}
let mut c = c_orig.clone();
c.curr_mark = 50;
assert!(!c.saw_prev_marked);
- vd[0].for_each_child(&mut c);
+ vd[0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
let mut c = c_orig.clone();
c.curr_mark = 60;
assert!(!c.saw_prev_marked);
- vd[0].for_each_child(&mut c);
+ vd[0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
let mut c = c_orig.clone();
c.curr_mark = 70;
assert!(!c.saw_prev_marked);
- vm[&0].for_each_child(&mut c);
+ vm[&0].descend_into_self(&mut c);
assert!(c.saw_prev_marked);
if PRINT { println!(""); }
for e in &ll {
c.curr_mark += 1;
c.saw_prev_marked = false;
- e.for_each_child(&mut c);
+ e.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
// break;
}
for b in &bh {
c.curr_mark += 1;
c.saw_prev_marked = false;
- b.for_each_child(&mut c);
+ b.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
// break;
}
for (k, _) in &btm {
c.curr_mark += 1;
c.saw_prev_marked = false;
- k.for_each_child(&mut c);
+ k.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
// break;
}
for b in &bts {
c.curr_mark += 1;
c.saw_prev_marked = false;
- b.for_each_child(&mut c);
+ b.descend_into_self(&mut c);
assert!(c.saw_prev_marked);
// break;
}
+
+ if PRINT { println!(""); }
+
+ // Cycle 11: { rc0 -> (rc1, rc2), rc1 -> (), rc2 -> rc0 }
+ let (rc0, rc1, rc2): (RCRC, RCRC, RCRC);
+ rc0 = RCRC::new("rcrc0");
+ rc1 = RCRC::new("rcrc1");
+ rc2 = RCRC::new("rcrc2");
+ rc0.0.borrow_mut().children.0 = Some(&rc1);
+ rc0.0.borrow_mut().children.1 = Some(&rc2);
+ rc2.0.borrow_mut().children.0 = Some(&rc0);
+
+ let mut c = c_orig.clone();
+ c.control_bits = 0b1;
+ c.curr_mark = 110;
+ assert!(!c.saw_prev_marked);
+ rc0.descend_into_self(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // We want to take the previous Rc case and generalize it to Arc.
+ //
+ // We can use refcells if we're single-threaded (as this test is).
+ // If one were to generalize these constructions to a
+ // multi-threaded context, then it might seem like we could choose
+ // between either a RwLock or a Mutex to hold the owned arcs on
+ // each node.
+ //
+ // Part of the point of this test is to actually confirm that the
+ // cycle exists by traversing it. We can do that just fine with an
+ // RwLock (since we can grab the child pointers in read-only
+ // mode), but we cannot lock a std::sync::Mutex to guard reading
+ // from each node via the same pattern, since once you hit the
+ // cycle, you'll be trying to acquring the same lock twice.
+ // (We deal with this by exiting the traversal early if try_lock fails.)
+
+ // Cycle 12: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, refcells
+ let (arc0, arc1, arc2): (ARCRC, ARCRC, ARCRC);
+ arc0 = ARCRC::new("arcrc0");
+ arc1 = ARCRC::new("arcrc1");
+ arc2 = ARCRC::new("arcrc2");
+ arc0.0.borrow_mut().children.0 = Some(&arc1);
+ arc0.0.borrow_mut().children.1 = Some(&arc2);
+ arc2.0.borrow_mut().children.0 = Some(&arc0);
+
+ let mut c = c_orig.clone();
+ c.control_bits = 0b1;
+ c.curr_mark = 110;
+ assert!(!c.saw_prev_marked);
+ arc0.descend_into_self(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // Cycle 13: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, rwlocks
+ let (arc0, arc1, arc2): (ARCRW, ARCRW, ARCRW);
+ arc0 = ARCRW::new("arcrw0");
+ arc1 = ARCRW::new("arcrw1");
+ arc2 = ARCRW::new("arcrw2");
+ arc0.0.write().unwrap().children.0 = Some(&arc1);
+ arc0.0.write().unwrap().children.1 = Some(&arc2);
+ arc2.0.write().unwrap().children.0 = Some(&arc0);
+
+ let mut c = c_orig.clone();
+ c.control_bits = 0b1;
+ c.curr_mark = 110;
+ assert!(!c.saw_prev_marked);
+ arc0.descend_into_self(&mut c);
+ assert!(c.saw_prev_marked);
+
+ if PRINT { println!(""); }
+
+ // Cycle 14: { arc0 -> (arc1, arc2), arc1 -> (), arc2 -> arc0 }, mutexs
+ let (arc0, arc1, arc2): (ARCM, ARCM, ARCM);
+ arc0 = ARCM::new("arcm0");
+ arc1 = ARCM::new("arcm1");
+ arc2 = ARCM::new("arcm2");
+ arc0.1.lock().unwrap().children.0 = Some(&arc1);
+ arc0.1.lock().unwrap().children.1 = Some(&arc2);
+ arc2.1.lock().unwrap().children.0 = Some(&arc0);
+
+ let mut c = c_orig.clone();
+ c.control_bits = 0b1;
+ c.curr_mark = 110;
+ assert!(!c.saw_prev_marked);
+ arc0.descend_into_self(&mut c);
+ assert!(c.saw_prev_marked);
}
trait Named {
fn set_mark(&self, mark: u32) { self.mark.set(mark); }
}
+struct S2<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ next: Cell<(Option<&'a S2<'a>>, Option<&'a S2<'a>>)>,
+}
+
+impl<'a> Named for S2<'a> {
+ fn new<'b>(name: &'static str) -> S2<'b> {
+ S2 { name: name, mark: Cell::new(0), next: Cell::new((None, None)) }
+ }
+ fn name(&self) -> &str { self.name }
+}
+
+impl<'a> Marked<u32> for S2<'a> {
+ fn mark(&self) -> u32 { self.mark.get() }
+ fn set_mark(&self, mark: u32) {
+ self.mark.set(mark);
+ }
+}
+
struct V<'a> {
name: &'static str,
mark: Cell<u32>,
}
}
+#[derive(Clone)]
+struct RCRCData<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ children: (Option<&'a RCRC<'a>>, Option<&'a RCRC<'a>>),
+}
+#[derive(Clone)]
+struct RCRC<'a>(Rc<RefCell<RCRCData<'a>>>);
+
+impl<'a> Named for RCRC<'a> {
+ fn new(name: &'static str) -> Self {
+ RCRC(Rc::new(RefCell::new(RCRCData {
+ name: name, mark: Cell::new(0), children: (None, None), })))
+ }
+ fn name(&self) -> &str { self.0.borrow().name }
+}
+
+impl<'a> Marked<u32> for RCRC<'a> {
+ fn mark(&self) -> u32 { self.0.borrow().mark.get() }
+ fn set_mark(&self, mark: u32) { self.0.borrow().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for RCRC<'a> {
+ fn count_children(&self) -> usize { 2 }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
+ {
+ let children = &self.0.borrow().children;
+ let child = match index {
+ 0 => if let Some(child) = children.0 { child } else { return; },
+ 1 => if let Some(child) = children.1 { child } else { return; },
+ _ => panic!("bad children"),
+ };
+ // println!("S2 {} descending into child {} at index {}", self.name, child.name, index);
+ child.descend_into_self(context);
+ }
+}
+#[derive(Clone)]
+struct ARCRCData<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ children: (Option<&'a ARCRC<'a>>, Option<&'a ARCRC<'a>>),
+}
+#[derive(Clone)]
+struct ARCRC<'a>(Arc<RefCell<ARCRCData<'a>>>);
+
+impl<'a> Named for ARCRC<'a> {
+ fn new(name: &'static str) -> Self {
+ ARCRC(Arc::new(RefCell::new(ARCRCData {
+ name: name, mark: Cell::new(0), children: (None, None), })))
+ }
+ fn name(&self) -> &str { self.0.borrow().name }
+}
+
+impl<'a> Marked<u32> for ARCRC<'a> {
+ fn mark(&self) -> u32 { self.0.borrow().mark.get() }
+ fn set_mark(&self, mark: u32) { self.0.borrow().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for ARCRC<'a> {
+ fn count_children(&self) -> usize { 2 }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
+ {
+ let children = &self.0.borrow().children;
+ match index {
+ 0 => if let Some(ref child) = children.0 {
+ child.descend_into_self(context);
+ },
+ 1 => if let Some(ref child) = children.1 {
+ child.descend_into_self(context);
+ },
+ _ => panic!("bad children!"),
+ }
+ }
+}
+
+#[derive(Clone)]
+struct ARCMData<'a> {
+ mark: Cell<u32>,
+ children: (Option<&'a ARCM<'a>>, Option<&'a ARCM<'a>>),
+}
+
+#[derive(Clone)]
+struct ARCM<'a>(&'static str, Arc<Mutex<ARCMData<'a>>>);
+
+impl<'a> Named for ARCM<'a> {
+ fn new(name: &'static str) -> Self {
+ ARCM(name, Arc::new(Mutex::new(ARCMData {
+ mark: Cell::new(0), children: (None, None), })))
+ }
+ fn name(&self) -> &str { self.0 }
+}
+
+impl<'a> Marked<u32> for ARCM<'a> {
+ fn mark(&self) -> u32 { self.1.lock().unwrap().mark.get() }
+ fn set_mark(&self, mark: u32) { self.1.lock().unwrap().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for ARCM<'a> {
+ fn count_children(&self) -> usize { 2 }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
+ {
+ let ref children = if let Ok(data) = self.1.try_lock() {
+ data.children
+ } else { return; };
+ match index {
+ 0 => if let Some(ref child) = children.0 {
+ child.descend_into_self(context);
+ },
+ 1 => if let Some(ref child) = children.1 {
+ child.descend_into_self(context);
+ },
+ _ => panic!("bad children!"),
+ }
+ }
+}
+
+#[derive(Clone)]
+struct ARCRWData<'a> {
+ name: &'static str,
+ mark: Cell<u32>,
+ children: (Option<&'a ARCRW<'a>>, Option<&'a ARCRW<'a>>),
+}
+
+#[derive(Clone)]
+struct ARCRW<'a>(Arc<RwLock<ARCRWData<'a>>>);
+
+impl<'a> Named for ARCRW<'a> {
+ fn new(name: &'static str) -> Self {
+ ARCRW(Arc::new(RwLock::new(ARCRWData {
+ name: name, mark: Cell::new(0), children: (None, None), })))
+ }
+ fn name(&self) -> &str { self.0.read().unwrap().name }
+}
+
+impl<'a> Marked<u32> for ARCRW<'a> {
+ fn mark(&self) -> u32 { self.0.read().unwrap().mark.get() }
+ fn set_mark(&self, mark: u32) { self.0.read().unwrap().mark.set(mark); }
+}
+
+impl<'a> Children<'a> for ARCRW<'a> {
+ fn count_children(&self) -> usize { 2 }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
+ {
+ let children = &self.0.read().unwrap().children;
+ match index {
+ 0 => if let Some(ref child) = children.0 {
+ child.descend_into_self(context);
+ },
+ 1 => if let Some(ref child) = children.1 {
+ child.descend_into_self(context);
+ },
+ _ => panic!("bad children!"),
+ }
+ }
+}
trait Context {
+ fn next_index(&mut self, len: usize) -> usize;
fn should_act(&self) -> bool;
fn increase_visited(&mut self);
fn increase_skipped(&mut self);
}
trait Children<'a> {
- fn for_each_child<C>(&self, context: &mut C)
+ fn count_children(&self) -> usize;
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
where C: Context + PrePost<Self>, Self: Sized;
+ fn next_child<C>(&self, context: &mut C)
+ where C: Context + PrePost<Self>, Self: Sized
+ {
+ let index = context.next_index(self.count_children());
+ self.descend_one_child(context, index);
+ }
+
fn descend_into_self<C>(&self, context: &mut C)
where C: Context + PrePost<Self>, Self: Sized
{
if context.should_act() {
context.increase_visited();
context.increase_depth();
- self.for_each_child(context);
+ self.next_child(context);
context.decrease_depth();
} else {
context.hit_limit(self);
}
impl<'a> Children<'a> for S<'a> {
- fn for_each_child<C>(&self, context: &mut C)
- where C: Context + PrePost<S<'a>>
+ fn count_children(&self) -> usize { 1 }
+ fn descend_one_child<C>(&self, context: &mut C, _: usize)
+ where C: Context + PrePost<Self>, Self: Sized {
+ self.descend(&self.next, context);
+ }
+}
+
+impl<'a> Children<'a> for S2<'a> {
+ fn count_children(&self) -> usize { 2 }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
{
- self.descend(&self.next, context);
+ let children = self.next.get();
+ let child = match index {
+ 0 => if let Some(child) = children.0 { child } else { return; },
+ 1 => if let Some(child) = children.1 { child } else { return; },
+ _ => panic!("bad children"),
+ };
+ // println!("S2 {} descending into child {} at index {}", self.name, child.name, index);
+ child.descend_into_self(context);
}
}
impl<'a> Children<'a> for V<'a> {
- fn for_each_child<C>(&self, context: &mut C)
- where C: Context + PrePost<V<'a>>
+ fn count_children(&self) -> usize { self.contents.len() }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
{
- for r in &self.contents {
- self.descend(r, context);
+ if let Some(child) = self.contents[index].get() {
+ child.descend_into_self(context);
}
}
}
impl<'a> Children<'a> for H<'a> {
- fn for_each_child<C>(&self, context: &mut C)
- where C: Context + PrePost<H<'a>>
+ fn count_children(&self) -> usize { 1 }
+ fn descend_one_child<C>(&self, context: &mut C, _: usize)
+ where C: Context + PrePost<Self>, Self: Sized
{
self.descend(&self.next, context);
}
}
impl<'a> Children<'a> for HM<'a> {
- fn for_each_child<C>(&self, context: &mut C)
- where C: Context + PrePost<HM<'a>>
+ fn count_children(&self) -> usize {
+ if let Some(m) = self.contents.get() { 2 * m.iter().count() } else { 0 }
+ }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
{
if let Some(ref hm) = self.contents.get() {
- for (k, v) in hm.iter() {
- for r in &[k, v] {
- r.descend_into_self(context);
- }
+ for (k, v) in hm.iter().nth(index / 2) {
+ [k, v][index % 2].descend_into_self(context);
}
}
}
}
impl<'a> Children<'a> for VD<'a> {
- fn for_each_child<C>(&self, context: &mut C)
- where C: Context + PrePost<VD<'a>>
+ fn count_children(&self) -> usize {
+ if let Some(d) = self.contents.get() { d.iter().count() } else { 0 }
+ }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
+ where C: Context + PrePost<Self>, Self: Sized
{
if let Some(ref vd) = self.contents.get() {
- for r in vd.iter() {
+ for r in vd.iter().nth(index) {
r.descend_into_self(context);
}
}
}
impl<'a> Children<'a> for VM<'a> {
- fn for_each_child<C>(&self, context: &mut C)
+ fn count_children(&self) -> usize {
+ if let Some(m) = self.contents.get() { m.iter().count() } else { 0 }
+ }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
where C: Context + PrePost<VM<'a>>
{
if let Some(ref vd) = self.contents.get() {
- for (_idx, r) in vd.iter() {
+ for (_idx, r) in vd.iter().nth(index) {
r.descend_into_self(context);
}
}
}
impl<'a> Children<'a> for LL<'a> {
- fn for_each_child<C>(&self, context: &mut C)
+ fn count_children(&self) -> usize {
+ if let Some(l) = self.contents.get() { l.iter().count() } else { 0 }
+ }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
where C: Context + PrePost<LL<'a>>
{
if let Some(ref ll) = self.contents.get() {
- for r in ll.iter() {
+ for r in ll.iter().nth(index) {
r.descend_into_self(context);
}
}
}
impl<'a> Children<'a> for BH<'a> {
- fn for_each_child<C>(&self, context: &mut C)
+ fn count_children(&self) -> usize {
+ if let Some(h) = self.contents.get() { h.iter().count() } else { 0 }
+ }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
where C: Context + PrePost<BH<'a>>
{
if let Some(ref bh) = self.contents.get() {
- for r in bh.iter() {
+ for r in bh.iter().nth(index) {
r.descend_into_self(context);
}
}
}
impl<'a> Children<'a> for BTM<'a> {
- fn for_each_child<C>(&self, context: &mut C)
+ fn count_children(&self) -> usize {
+ if let Some(m) = self.contents.get() { 2 * m.iter().count() } else { 0 }
+ }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
where C: Context + PrePost<BTM<'a>>
{
if let Some(ref bh) = self.contents.get() {
- for (k, v) in bh.iter() {
- for r in &[k, v] {
- r.descend_into_self(context);
- }
+ for (k, v) in bh.iter().nth(index / 2) {
+ [k, v][index % 2].descend_into_self(context);
}
}
}
}
impl<'a> Children<'a> for BTS<'a> {
- fn for_each_child<C>(&self, context: &mut C)
+ fn count_children(&self) -> usize {
+ if let Some(s) = self.contents.get() { s.iter().count() } else { 0 }
+ }
+ fn descend_one_child<C>(&self, context: &mut C, index: usize)
where C: Context + PrePost<BTS<'a>>
{
if let Some(ref bh) = self.contents.get() {
- for r in bh.iter() {
+ for r in bh.iter().nth(index) {
r.descend_into_self(context);
}
}
skipped: usize,
curr_mark: u32,
saw_prev_marked: bool,
+ control_bits: u64,
}
impl Context for ContextData {
+ fn next_index(&mut self, len: usize) -> usize {
+ if len < 2 { return 0; }
+ let mut pow2 = len.next_power_of_two();
+ let _pow2_orig = pow2;
+ let mut idx = 0;
+ let mut bits = self.control_bits;
+ while pow2 > 1 {
+ idx = (idx << 1) | (bits & 1) as usize;
+ bits = bits >> 1;
+ pow2 = pow2 >> 1;
+ }
+ idx = idx % len;
+ // println!("next_index({} [{:b}]) says {}, pre(bits): {:b} post(bits): {:b}",
+ // len, _pow2_orig, idx, self.control_bits, bits);
+ self.control_bits = bits;
+ return idx;
+ }
fn should_act(&self) -> bool {
self.curr_depth < self.max_depth && self.visited < self.max_visits
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Check that a arena (TypedArena) can carry elements whose drop
+// Check that an arena (TypedArena) can carry elements whose drop
// methods might access borrowed data, as long as the borrowed data
// has lifetime that strictly outlives the arena itself.
//
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Empty struct defined with braces add names into type namespace
+// Empty struct defined without braces add names into both type and value namespaces
+
+#![feature(braced_empty_structs)]
+
+struct Empty1 {}
+struct Empty2;
+struct Empty3 {}
+const Empty3: Empty3 = Empty3 {};
+
+enum E {
+ Empty4 {},
+ Empty5,
+}
+
+fn main() {
+ let e1: Empty1 = Empty1 {};
+ let e2: Empty2 = Empty2 {};
+ let e2: Empty2 = Empty2;
+ let e3: Empty3 = Empty3 {};
+ let e3: Empty3 = Empty3;
+ let e4: E = E::Empty4 {};
+ // let e5: E = E::Empty5 {}; // Issue #28692
+ let e5: E = E::Empty5;
+
+ match e1 {
+ Empty1 {} => {}
+ }
+ match e2 {
+ Empty2 {} => {}
+ }
+ match e3 {
+ Empty3 {} => {}
+ }
+ match e4 {
+ E::Empty4 {} => {}
+ _ => {}
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 {} => {}
+ // _ => {}
+ // }
+
+ match e1 {
+ Empty1 { .. } => {}
+ }
+ match e2 {
+ Empty2 { .. } => {}
+ }
+ match e3 {
+ Empty3 { .. } => {}
+ }
+ match e4 {
+ E::Empty4 { .. } => {}
+ _ => {}
+ }
+ // Issue #28692
+ // match e5 {
+ // E::Empty5 { .. } => {}
+ // _ => {}
+ // }
+
+ match e2 {
+ Empty2 => {}
+ }
+ match e3 {
+ Empty3 => {}
+ }
+ match e5 {
+ E::Empty5 => {}
+ _ => {}
+ }
+
+ let e11: Empty1 = Empty1 { ..e1 };
+ let e22: Empty2 = Empty2 { ..e2 };
+ let e33: Empty3 = Empty3 { ..e3 };
+}
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Test that negating unsigned integers is gated by `negate_unsigned` feature
-// gate
-
-struct S;
-impl std::ops::Neg for S {
- type Output = u32;
- fn neg(self) -> u32 { 0 }
-}
-
-const _MAX: usize = -1;
-//~^ WARN unary negation of unsigned integers will be feature gated in the future
-
-fn main() {
- let a = -1;
- //~^ WARN unary negation of unsigned integers will be feature gated in the future
- let _b : u8 = a; // for infering variable a to u8.
-
- -a;
- //~^ WARN unary negation of unsigned integers will be feature gated in the future
-
- let _d = -1u8;
- //~^ WARN unary negation of unsigned integers will be feature gated in the future
-
- for _ in -10..10u8 {}
- //~^ WARN unary negation of unsigned integers will be feature gated in the future
-
- -S; // should not trigger the gate; issue 26840
-}
t!(format!("{:?}", 10_usize), "10");
t!(format!("{:?}", "true"), "\"true\"");
t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\"");
+ t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"),
+ r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#);
+ t!(format!("{:?}", "foo\0bar\x01baz\u{3b1}q\u{75}x"),
+ r#""foo\u{0}bar\u{1}baz\u{3b1}qux""#);
t!(format!("{:o}", 10_usize), "12");
t!(format!("{:x}", 10_usize), "a");
t!(format!("{:X}", 10_usize), "A");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Ensure that an user-defined type admits multiple inherent methods
+// Ensure that a user-defined type admits multiple inherent methods
// with the same name, which can be called on values that have a
// precise enough type to allow distinguishing between the methods.
pub fn main() {
fn f() {
};
- let _: Box<fn()> = box() (f as fn());
+ let _: Box<fn()> = box (f as fn());
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that static methods can be invoked on `type` aliases
+
+#![allow(unused_variables)]
+
+pub mod foo {
+ pub mod bar {
+ pub mod baz {
+ pub struct Qux;
+
+ impl Qux {
+ pub fn new() {}
+ }
+ }
+ }
+}
+
+fn main() {
+
+ type Ham = foo::bar::baz::Qux;
+ let foo = foo::bar::baz::Qux::new(); // invoke directly
+ let bar = Ham::new(); // invoke via type alias
+
+ type StringVec = Vec<String>;
+ let sv = StringVec::new();
+}
-
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-mod Foo { }
-struct Foo;
-impl Foo { }
-
-fn main() { }
fn main() {
let s = "abcbdef";
match_indices(s, |c: char| c == 'b')
- .collect::<Vec<(usize, usize)>>();
+ .collect::<Vec<_>>();
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//`#[cfg]` on struct field permits empty unusable struct
+
+#![feature(braced_empty_structs)]
+
+struct S {
+ #[cfg(untrue)]
+ a: int,
+}
+
+fn main() {
+ let s = S {};
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[allow(dead_code)]
+fn check(a: &str) {
+ let x = a as *const str;
+ x == x;
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn g<F>(_: F) where F: FnOnce(Option<F>) {}
+
+fn main() {
+ g(|_| { });
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::ops::Add;
+fn show(z: i32) {
+ println!("{}", z)
+}
+fn main() {
+ let x = 23;
+ let y = 42;
+ show(Add::add( x, y));
+ show(Add::add( x, &y));
+ show(Add::add(&x, y));
+ show(Add::add(&x, &y));
+ show( x + y);
+ show( x + &y);
+ show(&x + y);
+ show(&x + &y);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let x = Box::new([1, 2, 3]);
+ let y = x as Box<[i32]>;
+ println!("y: {:?}", y);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+use std::collections::hash_map::Entry::Vacant;
+
+pub fn foo() {
+ type F = Box<Fn(&()) + 'static>;
+ let mut map: HashMap<(), F> = HashMap::new();
+ let x: &mut F = match map.entry(()) {
+ Vacant(_) => unimplemented!(),
+ _ => unimplemented!()
+ };
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Test {}
+
+macro_rules! test {
+( $($name:ident)+) => (
+ impl<$($name: Test),*> Test for ($($name,)*) {
+ }
+)
+}
+
+test!(A B C);
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+use std::path::Path;
+
+fn main() {
+ let mut map = HashMap::new();
+ map.insert(Path::new("a"), 0);
+ map.get(Path::new("a"));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! id {
+ ($s: pat) => ($s);
+}
+
+fn main() {
+ match (Some(123), Some(456)) {
+ (id!(Some(a)), _) | (_, id!(Some(a))) => println!("{}", a),
+ _ => (),
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// Regression test for #24085. Errors were occuring in region
+// Regression test for #24085. Errors were occurring in region
// inference due to the requirement that `'a:b'`, which was getting
// incorrectly translated in connection with the closure below.
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(dead_code)]
+
+struct Foo;
+
+impl Foo {
+ fn new() -> Self { Foo }
+ fn bar() { Self::new(); }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::slice::Iter;
+use std::io::{Error, ErrorKind, Result};
+use std::vec::*;
+
+fn foo(it: &mut Iter<u8>) -> Result<u8> {
+ Ok(*it.next().unwrap())
+}
+
+fn bar() -> Result<u8> {
+ let data: Vec<u8> = Vec::new();
+
+ if true {
+ return Err(Error::new(ErrorKind::NotFound, "msg"));
+ }
+
+ let mut it = data.iter();
+ foo(&mut it)
+}
+
+fn main() {
+ bar();
+}
#![allow(non_camel_case_types)]
+#![feature(dropck_parametricity)]
+
trait UserDefined { }
impl UserDefined for i32 { }
macro_rules! impl_drop {
($Bound:ident, $Id:ident) => {
struct $Id<T:$Bound>(T);
- impl <T:$Bound> Drop for $Id<T> { fn drop(&mut self) { } }
+ impl <T:$Bound> Drop for $Id<T> {
+ #[unsafe_destructor_blind_to_params]
+ fn drop(&mut self) { }
+ }
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Foo(bool);
+const NEW_FALSE: bool = false;
+const STATIC_FOO: Foo = Foo(NEW_FALSE);
+
+pub fn main() {
+ match (Foo(false)) {
+ STATIC_FOO => 3,
+ _ => 11
+ };
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(rustc_private)]
+
+extern crate serialize;
+
+use serialize::{Encodable, Decodable};
+use std::fmt::Display;
+
+pub trait Entity : Decodable + Encodable + Sized {
+ type Key: Clone + Decodable + Encodable + ToString + Display + Eq + Ord + Sized;
+
+ fn id(&self) -> Self::Key;
+
+ fn find_by_id(id: Self::Key) -> Option<Self>;
+}
+
+pub struct DbRef<E: Entity> {
+ pub id: E::Key,
+}
+
+impl<E> DbRef<E> where E: Entity {
+ fn get(self) -> Option<E> {
+ E::find_by_id(self.id)
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Helper<'a, F: 'a>(&'a F);
+
+fn fix<F>(f: F) -> i32 where F: Fn(Helper<F>, i32) -> i32 {
+ f(Helper(&f), 8)
+}
+
+fn main() {
+ fix(|_, x| x);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Paramters { type SelfRef; }
+
+struct RP<'a> { _marker: std::marker::PhantomData<&'a ()> }
+struct BP;
+
+impl<'a> Paramters for RP<'a> { type SelfRef = &'a X<RP<'a>>; }
+impl Paramters for BP { type SelfRef = Box<X<BP>>; }
+
+pub struct Y;
+pub enum X<P: Paramters> {
+ Nothing,
+ SameAgain(P::SelfRef, Y)
+}
+
+fn main() {
+ let bnil: Box<X<BP>> = Box::new(X::Nothing);
+ let bx: Box<X<BP>> = Box::new(X::SameAgain(bnil, Y));
+ let rnil: X<RP> = X::Nothing;
+ let rx: X<RP> = X::SameAgain(&rnil, Y);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_consts)]
+
+trait HasNumber<T> {
+ const Number: usize;
+}
+
+enum One {}
+enum Two {}
+
+enum Foo {}
+
+impl<T> HasNumber<T> for One {
+ const Number: usize = 1;
+}
+
+impl<T> HasNumber<T> for Two {
+ const Number: usize = 2;
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(unsize, coerce_unsized)]
+
+// Verfies that PhantomData is ignored for DST coercions
+
+use std::marker::{Unsize, PhantomData};
+use std::ops::CoerceUnsized;
+
+struct MyRc<T: ?Sized> {
+ _ptr: *const T,
+ _boo: PhantomData<T>,
+}
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<MyRc<U>> for MyRc<T>{ }
+
+fn main() {
+ let data = [1, 2, 3];
+ let iter = data.iter();
+ let x = MyRc { _ptr: &iter, _boo: PhantomData };
+ let _y: MyRc<Iterator<Item=&u32>> = x;
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+pub struct Callbacks {
+ callbacks: Vec<Rc<RefCell<FnMut(i32)>>>,
+}
+
+impl Callbacks {
+ pub fn register<F: FnMut(i32)+'static>(&mut self, callback: F) {
+ self.callbacks.push(Rc::new(RefCell::new(callback)));
+ }
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+macro_rules! piece(
+ ($piece:pat) => ($piece);
+);
+
+enum Piece {A, B}
+
+fn main() {
+ match Piece::A {
+ piece!(pt@ Piece::A) | piece!(pt@ Piece::B) => {}
+ }
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S<T>(T) where [T; (||{}, 1).1]: Copy;
+
+fn main() {
+
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::rc::Rc;
+
+fn test1() -> Rc<for<'a> Fn(&'a usize) + 'static> {
+ if let Some(_) = Some(1) {
+ loop{}
+ } else {
+ loop{}
+ }
+}
+
+fn test2() -> *mut for<'a> Fn(&'a usize) + 'static {
+ if let Some(_) = Some(1) {
+ loop{}
+ } else {
+ loop{}
+ }
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[derive(Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+struct Array<T> {
+ f00: [T; 00],
+ f01: [T; 01],
+ f02: [T; 02],
+ f03: [T; 03],
+ f04: [T; 04],
+ f05: [T; 05],
+ f06: [T; 06],
+ f07: [T; 07],
+ f08: [T; 08],
+ f09: [T; 09],
+ f10: [T; 10],
+ f11: [T; 11],
+ f12: [T; 12],
+ f13: [T; 13],
+ f14: [T; 14],
+ f15: [T; 15],
+ f16: [T; 16],
+ f17: [T; 17],
+ f18: [T; 18],
+ f19: [T; 19],
+ f20: [T; 20],
+ f21: [T; 21],
+ f22: [T; 22],
+ f23: [T; 23],
+ f24: [T; 24],
+ f25: [T; 25],
+ f26: [T; 26],
+ f27: [T; 27],
+ f28: [T; 28],
+ f29: [T; 29],
+ f30: [T; 30],
+ f31: [T; 31],
+ f32: [T; 32],
+}
+
+// FIXME(#7622): merge with `Array` once `[T; N]: Clone` where `T: Clone`
+#[derive(Clone, Copy)]
+struct CopyArray<T: Copy> {
+ f00: [T; 00],
+ f01: [T; 01],
+ f02: [T; 02],
+ f03: [T; 03],
+ f04: [T; 04],
+ f05: [T; 05],
+ f06: [T; 06],
+ f07: [T; 07],
+ f08: [T; 08],
+ f09: [T; 09],
+ f10: [T; 10],
+ f11: [T; 11],
+ f12: [T; 12],
+ f13: [T; 13],
+ f14: [T; 14],
+ f15: [T; 15],
+ f16: [T; 16],
+ f17: [T; 17],
+ f18: [T; 18],
+ f19: [T; 19],
+ f20: [T; 20],
+ f21: [T; 21],
+ f22: [T; 22],
+ f23: [T; 23],
+ f24: [T; 24],
+ f25: [T; 25],
+ f26: [T; 26],
+ f27: [T; 27],
+ f28: [T; 28],
+ f29: [T; 29],
+ f30: [T; 30],
+ f31: [T; 31],
+ f32: [T; 32],
+}
+
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+struct Fn<A, B, C, D, E, F, G, H, I, J, K, L> {
+ f00: fn(),
+ f01: fn(A),
+ f02: fn(A, B),
+ f03: fn(A, B, C),
+ f04: fn(A, B, C, D),
+ f05: fn(A, B, C, D, E),
+ f06: fn(A, B, C, D, E, F),
+ f07: fn(A, B, C, D, E, F, G),
+ f08: fn(A, B, C, D, E, F, G, H),
+ f09: fn(A, B, C, D, E, F, G, H, I),
+ f10: fn(A, B, C, D, E, F, G, H, I, J),
+ f11: fn(A, B, C, D, E, F, G, H, I, J, K),
+ f12: fn(A, B, C, D, E, F, G, H, I, J, K, L),
+}
+
+#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
+struct Tuple<A, B, C, D, E, F, G, H, I, J, K, L> {
+ f00: (),
+ f01: (A),
+ f02: (A, B),
+ f03: (A, B, C),
+ f04: (A, B, C, D),
+ f05: (A, B, C, D, E),
+ f06: (A, B, C, D, E, F),
+ f07: (A, B, C, D, E, F, G),
+ f08: (A, B, C, D, E, F, G, H),
+ f09: (A, B, C, D, E, F, G, H, I),
+ f10: (A, B, C, D, E, F, G, H, I, J),
+ f11: (A, B, C, D, E, F, G, H, I, J, K),
+ f12: (A, B, C, D, E, F, G, H, I, J, K, L),
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+
+#[derive(Copy, Clone)]
+pub struct Quad { a: u64, b: u64, c: u64, d: u64 }
+
+mod rustrt {
+ use super::Quad;
+
+ #[link(name = "rust_test_helpers")]
+ extern {
+ pub fn get_c_many_params(_: *const (), _: *const (),
+ _: *const (), _: *const (), f: Quad) -> u64;
+ }
+}
+
+fn test() {
+ unsafe {
+ let null = std::ptr::null();
+ let q = Quad {
+ a: 1,
+ b: 2,
+ c: 3,
+ d: 4
+ };
+ assert_eq!(rustrt::get_c_many_params(null, null, null, null, q), q.c);
+ }
+}
+
+pub fn main() {
+ test();
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(const_fn)]
+
+fn main() {}
+
+const fn size_ofs(_: usize) {}
+const fn size_ofs2(_foo: usize) {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-pretty : (#23623) problems with newlines before // comments
+
+pub struct Foo;
+
+pub fn get_foo2<'a>(foo: &'a mut Option<&'a mut Foo>) -> &'a mut Foo {
+ match foo {
+ // Ensure that this is not considered a move, but rather a reborrow.
+ &mut Some(ref mut x) => *x,
+ &mut None => panic!(),
+ }
+}
+
+fn main() {
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub type Session = i32;
+pub struct StreamParser<'a, T> {
+ _tokens: T,
+ _session: &'a mut Session,
+}
+
+impl<'a, T> StreamParser<'a, T> {
+ pub fn thing(&mut self) -> bool { true }
+}
+
+pub fn parse_stream<T: Iterator<Item=i32>, U, F>(
+ _session: &mut Session, _tokens: T, _f: F) -> U
+ where F: Fn(&mut StreamParser<T>) -> U { panic!(); }
+
+pub fn thing(session: &mut Session) {
+ let mut stream = vec!(1, 2, 3).into_iter();
+
+ let _b = parse_stream(session,
+ stream.by_ref(),
+ // replacing the above with the following fixes it
+ //&mut stream,
+ |p| p.thing());
+
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Test { type T; }
+
+impl Test for u32 {
+ type T = i32;
+}
+
+pub mod export {
+ #[no_mangle]
+ pub extern "C" fn issue_28983(t: <u32 as ::Test>::T) -> i32 { t*3 }
+}
+
+// to test both exporting and importing functions, import
+// a function from ourselves.
+extern "C" {
+ fn issue_28983(t: <u32 as Test>::T) -> i32;
+}
+
+fn main() {
+ assert_eq!(export::issue_28983(2), 6);
+ assert_eq!(unsafe { issue_28983(3) }, 9);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct Xyz<'a, V> {
+ pub v: (V, &'a u32),
+}
+
+pub fn eq<'a, 's, 't, V>(this: &'s Xyz<'a, V>, other: &'t Xyz<'a, V>) -> bool
+ where V: PartialEq {
+ this.v == other.v
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test ensures that each pointer type `P<X>` is covariant in `X`.
+
+use std::rc::Rc;
+use std::sync::Arc;
+
+fn a<'r>(x: Box<&'static str>) -> Box<&'r str> {
+ x
+}
+
+fn b<'r, 'w>(x: &'w &'static str) -> &'w &'r str {
+ x
+}
+
+fn c<'r>(x: Arc<&'static str>) -> Arc<&'r str> {
+ x
+}
+
+fn d<'r>(x: Rc<&'static str>) -> Rc<&'r str> {
+ x
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct Chan;
+pub struct ChanSelect<'c, T> {
+ chans: Vec<(&'c Chan, T)>,
+}
+impl<'c, T> ChanSelect<'c, T> {
+ pub fn add_recv_ret(&mut self, chan: &'c Chan, ret: T)
+ {
+ self.chans.push((chan, ret));
+ }
+}
+fn main() {}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test ensures that vec.into_iter does not overconstrain element lifetime.
+
+pub fn main() {
+ original_report();
+ revision_1();
+ revision_2();
+}
+
+fn original_report() {
+ drop(vec![&()].into_iter())
+}
+
+fn revision_1() {
+ // below is what above `vec!` expands into at time of this writing.
+ drop(<[_]>::into_vec(::std::boxed::Box::new([&()])).into_iter())
+}
+
+fn revision_2() {
+ drop((match (Vec::new(), &()) { (mut v, b) => { v.push(b); v } }).into_iter())
+}
// let y = box ({a: 4});
// let z = box ({a: 4} as it);
// let z = box ({a: true} as it);
- let z: Box<_> = box () (box true as Box<it>);
+ let z: Box<_> = box (box true as Box<it>);
// x.f();
// y.f();
// (*z).f();
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// zip!(a1,a2,a3,a4) is equivalent to:
+// a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4))
+macro_rules! zip {
+ // Entry point
+ ([$a:expr, $b:expr, $($rest:expr),*]) => {
+ zip!([$($rest),*], $a.zip($b), (x,y), [x,y])
+ };
+
+ // Intermediate steps to build the zipped expression, the match pattern, and
+ // and the output tuple of the closure, using macro hygene to repeatedly
+ // introduce new variables named 'x'.
+ ([$a:expr, $($rest:expr),*], $zip:expr, $pat:pat, [$($flat:expr),*]) => {
+ zip!([$($rest),*], $zip.zip($a), ($pat,x), [$($flat),*, x])
+ };
+
+ // Final step
+ ([], $zip:expr, $pat:pat, [$($flat:expr),+]) => {
+ $zip.map(|$pat| ($($flat),+))
+ };
+
+ // Comma
+ ([$a:expr], $zip:expr, $pat:pat, [$($flat:expr),*]) => {
+ zip!([$a,], $zip, $pat, [$($flat),*])
+ };
+}
+
+fn main() {
+ let p1 = vec![1i32, 2].into_iter();
+ let p2 = vec!["10", "20"].into_iter();
+ let p3 = vec![100u16, 200].into_iter();
+ let p4 = vec![1000i64, 2000].into_iter();
+
+ let e = zip!([p1,p2,p3,p4]).collect::<Vec<_>>();
+ assert_eq!(e[0], (1i32,"10",100u16,1000i64));
+}
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This used to segfault #30081
+
+pub enum Instruction {
+ Increment(i8),
+ Loop(Box<Box<()>>),
+}
+
+fn main() {
+ let instrs: Option<(u8, Box<Instruction>)> = None;
+ instrs.into_iter()
+ .map(|(_, instr)| instr)
+ .map(|instr| match *instr { _other => {} })
+ .last();
+}
print!("{}", stringify!($field_tl));
print!(", ");
)+
- // FIXME: #9970
- print!("{}", "]\n");
+ print!("]\n");
})
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Example taken from RFC 1238 text
+
+// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
+// #examples-of-code-that-must-continue-to-work
+
+use std::cell::Cell;
+
+struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+
+fn main() {
+ let mut data = Vec::new();
+ data.push(Concrete(0, Cell::new(None)));
+ data.push(Concrete(0, Cell::new(None)));
+
+ data[0].1.set(Some(&data[1]));
+ data[1].1.set(Some(&data[0]));
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Example taken from RFC 1238 text
+
+// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
+// #examples-of-code-that-must-continue-to-work
+
+use std::cell::Cell;
+
+struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+
+struct Foo<T> { data: Vec<T> }
+
+fn main() {
+ let mut foo = Foo { data: Vec::new() };
+ foo.data.push(Concrete(0, Cell::new(None)));
+ foo.data.push(Concrete(0, Cell::new(None)));
+
+ foo.data[0].1.set(Some(&foo.data[1]));
+ foo.data[1].1.set(Some(&foo.data[0]));
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Example taken from RFC 1238 text
+
+// https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
+// #example-of-the-unguarded-escape-hatch
+
+#![feature(dropck_parametricity)]
+use std::cell::Cell;
+
+struct Concrete<'a>(u32, Cell<Option<&'a Concrete<'a>>>);
+
+struct Foo<T> { data: Vec<T> }
+
+impl<T> Drop for Foo<T> {
+ // Below is the UGEH attribute
+ #[unsafe_destructor_blind_to_params]
+ fn drop(&mut self) { }
+}
+
+fn main() {
+ let mut foo = Foo { data: Vec::new() };
+ foo.data.push(Concrete(0, Cell::new(None)));
+ foo.data.push(Concrete(0, Cell::new(None)));
+
+ foo.data[0].1.set(Some(&foo.data[1]));
+ foo.data[1].1.set(Some(&foo.data[0]));
+}
+
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Demonstrate the use of the unguarded escape hatch with a lifetime param
+// to assert that destructor will not access any dead data.
+//
+// Compare with compile-fail/issue28498-reject-lifetime-param.rs
+
+#![feature(dropck_parametricity)]
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<'a>(u32, &'a ScribbleOnDrop);
+
+impl<'a> Drop for Foo<'a> {
+ #[unsafe_destructor_blind_to_params]
+ fn drop(&mut self) {
+ // Use of `unsafe_destructor_blind_to_params` is sound,
+ // because destructor never accesses `self.1`.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped);
+ foo1 = Foo(1, &first_dropped);
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Demonstrate the use of the unguarded escape hatch with a type param in negative position
+// to assert that destructor will not access any dead data.
+//
+// Compare with compile-fail/issue28498-reject-lifetime-param.rs
+
+// Demonstrate that a type param in negative position causes dropck to reject code
+// that might indirectly access previously dropped value.
+//
+// Compare with run-pass/issue28498-ugeh-with-passed-to-fn.rs
+
+#![feature(dropck_parametricity)]
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T>(u32, T, Box<for <'r> fn(&'r T) -> String>);
+
+impl<T> Drop for Foo<T> {
+ #[unsafe_destructor_blind_to_params]
+ fn drop(&mut self) {
+ // Use of `unsafe_destructor_blind_to_params` is sound,
+ // because destructor never passes a `self.1` to the callback
+ // (in `self.2`) despite having it available.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn callback(s: & &ScribbleOnDrop) -> String { format!("{:?}", s) }
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped, Box::new(callback));
+ foo1 = Foo(1, &first_dropped, Box::new(callback));
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Demonstrate the use of the unguarded escape hatch with a trait bound
+// to assert that destructor will not access any dead data.
+//
+// Compare with compile-fail/issue28498-reject-trait-bound.rs
+
+#![feature(dropck_parametricity)]
+
+use std::fmt;
+
+#[derive(Debug)]
+struct ScribbleOnDrop(String);
+
+impl Drop for ScribbleOnDrop {
+ fn drop(&mut self) {
+ self.0 = format!("DROPPED");
+ }
+}
+
+struct Foo<T:fmt::Debug>(u32, T);
+
+impl<T:fmt::Debug> Drop for Foo<T> {
+ #[unsafe_destructor_blind_to_params]
+ fn drop(&mut self) {
+ // Use of `unsafe_destructor_blind_to_params` is sound,
+ // because destructor never accesses the `Debug::fmt` method
+ // of `T`, despite having it available.
+ println!("Dropping Foo({}, _)", self.0);
+ }
+}
+
+fn main() {
+ let (last_dropped, foo0);
+ let (foo1, first_dropped);
+
+ last_dropped = ScribbleOnDrop(format!("last"));
+ first_dropped = ScribbleOnDrop(format!("first"));
+ foo0 = Foo(0, &last_dropped);
+ foo1 = Foo(1, &first_dropped);
+
+ println!("foo0.1: {:?} foo1.1: {:?}", foo0.1, foo1.1);
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-test #9383
-
// shouldn't affect evaluation of $ex:
macro_rules! bad_macro {
($ex:expr) => ({(|_x| { $ex }) (9) })
}
pub fn main() {
- let x: Box<isize> = box(HEAP) 2;
+ let x: Box<isize> = in HEAP { 2 };
let y: Box<isize> = box 2;
- let b: Box<isize> = box()(1 + 2);
- let c = box()(3 + 4);
+ let b: Box<isize> = box (1 + 2);
+ let c = box (3 + 4);
let s: Box<Structure> = box Structure {
x: 3,
+++ /dev/null
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// Basic sanity check for `push_unsafe!(EXPR)` and
-// `pop_unsafe!(EXPR)`: we can call unsafe code when there are a
-// positive number of pushes in the stack, or if we are within a
-// normal `unsafe` block, but otherwise cannot.
-
-// ignore-pretty because the `push_unsafe!` and `pop_unsafe!` macros
-// are not integrated with the pretty-printer.
-
-#![feature(pushpop_unsafe)]
-
-static mut X: i32 = 0;
-
-unsafe fn f() { X += 1; return; }
-fn g() { unsafe { X += 1_000; } return; }
-
-fn check_reset_x(x: i32) -> bool {
- #![allow(unused_parens)] // dont you judge my style choices!
- unsafe {
- let ret = (x == X);
- X = 0;
- ret
- }
-}
-
-fn main() {
- // double-check test infrastructure
- assert!(check_reset_x(0));
- unsafe { f(); }
- assert!(check_reset_x(1));
- assert!(check_reset_x(0));
- { g(); }
- assert!(check_reset_x(1000));
- assert!(check_reset_x(0));
- unsafe { f(); g(); g(); }
- assert!(check_reset_x(2001));
-
- push_unsafe!( { f(); pop_unsafe!( g() ) } );
- assert!(check_reset_x(1_001));
- push_unsafe!( { g(); pop_unsafe!( unsafe { f(); f(); } ) } );
- assert!(check_reset_x(1_002));
-
- unsafe { push_unsafe!( { f(); pop_unsafe!( { f(); f(); } ) } ); }
- assert!(check_reset_x(3));
- push_unsafe!( { f(); push_unsafe!( { pop_unsafe!( { f(); f(); f(); } ) } ); } );
- assert!(check_reset_x(4));
-}
impl<'t> MakerTrait for Box<Trait<'t>+'static> {
fn mk() -> Box<Trait<'t>+'static> {
- let tup: Box<(isize, isize)> = box() (4,5);
+ let tup: Box<(isize, isize)> = box (4,5);
tup as Box<Trait>
}
}
extern crate sepcomp_cci_lib;
-use sepcomp_cci_lib::{cci_fn, CCI_STATIC};
+use sepcomp_cci_lib::{cci_fn, CCI_CONST};
fn call1() -> usize {
- cci_fn() + CCI_STATIC
+ cci_fn() + CCI_CONST
}
mod a {
- use sepcomp_cci_lib::{cci_fn, CCI_STATIC};
+ use sepcomp_cci_lib::{cci_fn, CCI_CONST};
pub fn call2() -> usize {
- cci_fn() + CCI_STATIC
+ cci_fn() + CCI_CONST
}
}
mod b {
- use sepcomp_cci_lib::{cci_fn, CCI_STATIC};
+ use sepcomp_cci_lib::{cci_fn, CCI_CONST};
pub fn call3() -> usize {
- cci_fn() + CCI_STATIC
+ cci_fn() + CCI_CONST
}
}
// Check that we do *not* overflow on a number of edge cases.
// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)
-// (Work around constant-evaluation)
-fn id<T>(x: T) -> T { x }
-
fn main() {
test_left_shift();
test_right_shift();
macro_rules! tests {
($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
- let x = (1 as $iN) << id(0);
+ let x = (1 as $iN) << 0;
assert_eq!(x, 1);
- let x = (1 as $uN) << id(0);
+ let x = (1 as $uN) << 0;
assert_eq!(x, 1);
- let x = (1 as $iN) << id($max_rhs);
+ let x = (1 as $iN) << $max_rhs;
assert_eq!(x, $expect_i);
- let x = (1 as $uN) << id($max_rhs);
+ let x = (1 as $uN) << $max_rhs;
assert_eq!(x, $expect_u);
// high-order bits on LHS are silently discarded without panic.
- let x = (3 as $iN) << id($max_rhs);
+ let x = (3 as $iN) << $max_rhs;
assert_eq!(x, $expect_i);
- let x = (3 as $uN) << id($max_rhs);
+ let x = (3 as $uN) << $max_rhs;
assert_eq!(x, $expect_u);
} }
}
- let x = 1_i8 << id(0);
+ let x = 1_i8 << 0;
assert_eq!(x, 1);
- let x = 1_u8 << id(0);
+ let x = 1_u8 << 0;
assert_eq!(x, 1);
- let x = 1_i8 << id(7);
+ let x = 1_i8 << 7;
assert_eq!(x, std::i8::MIN);
- let x = 1_u8 << id(7);
+ let x = 1_u8 << 7;
assert_eq!(x, 0x80);
// high-order bits on LHS are silently discarded without panic.
- let x = 3_i8 << id(7);
+ let x = 3_i8 << 7;
assert_eq!(x, std::i8::MIN);
- let x = 3_u8 << id(7);
+ let x = 3_u8 << 7;
assert_eq!(x, 0x80);
// above is (approximately) expanded from:
($iN:ty, $uN:ty, $max_rhs:expr,
$signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
{ {
- let x = (1 as $iN) >> id(0);
+ let x = (1 as $iN) >> 0;
assert_eq!(x, 1);
- let x = (1 as $uN) >> id(0);
+ let x = (1 as $uN) >> 0;
assert_eq!(x, 1);
- let x = ($highbit_i) >> id($max_rhs-1);
+ let x = ($highbit_i) >> $max_rhs-1;
assert_eq!(x, 1);
- let x = ($highbit_u) >> id($max_rhs);
+ let x = ($highbit_u) >> $max_rhs;
assert_eq!(x, 1);
// sign-bit is carried by arithmetic right shift
- let x = ($signbit_i) >> id($max_rhs);
+ let x = ($signbit_i) >> $max_rhs;
assert_eq!(x, -1);
// low-order bits on LHS are silently discarded without panic.
- let x = ($highbit_i + 1) >> id($max_rhs-1);
+ let x = ($highbit_i + 1) >> $max_rhs-1;
assert_eq!(x, 1);
- let x = ($highbit_u + 1) >> id($max_rhs);
+ let x = ($highbit_u + 1) >> $max_rhs;
assert_eq!(x, 1);
- let x = ($signbit_i + 1) >> id($max_rhs);
+ let x = ($signbit_i + 1) >> $max_rhs;
assert_eq!(x, -1);
} }
}
}
all_sync_send!(EnumSet::<Foo>::new(), iter);
- all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, drain, into_iter);
+ all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, into_iter);
+ is_sync_send!(VecDeque::<usize>::new(), drain(..));
all_sync_send!(Vec::<usize>::new(), into_iter);
is_sync_send!(Vec::<usize>::new(), drain(..));
}
pub fn main() {
- let a = box() () as Box<Trait<u8, u8>>;
+ let a = box () as Box<Trait<u8, u8>>;
assert_eq!(a.method(Type::Constant((1, 2))), 0);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(negate_unsigned)]
+
pub fn main() {
let a = 1;
let a_neg: i8 = -a;
use std::cell::Cell;
-#[derive(Show)]
+#[derive(Debug)]
struct C<'a> {
v: Vec<Cell<Option<&'a C<'a>>>>,
}
use std::cell::Cell;
-#[derive(Show)]
+#[derive(Debug)]
struct Refs<'a> {
v: Vec<Cell<Option<&'a C<'a>>>>,
}
-#[derive(Show)]
+#[derive(Debug)]
struct C<'a> {
refs: Refs<'a>,
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(num_wrapping)]
-
// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}.
use std::{i8, i16, i32, i64, isize};
#![feature(std_misc)]
-pub type HANDLE = u32;
+pub type HANDLE = usize;
pub type DWORD = u32;
pub type SIZE_T = u32;
pub type LPVOID = usize;
/// retained.
///
/// ```rust
-/// mod to_make_deriving_work { // FIXME #4913
-///
/// # #[derive(PartialEq)] // invisible
/// # struct Foo; // invisible
///
/// let x = Bar(Foo);
/// assert_eq!(x, x); // check that the derivings worked
/// }
-///
-/// }
/// ```
pub fn foo() {}