12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480 |
- //===--- SemaDeclAttr.cpp - Declaration Attribute Handling ----------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file implements decl-related attribute processing.
- //
- //===----------------------------------------------------------------------===//
- #include "clang/AST/ASTConsumer.h"
- #include "clang/AST/ASTContext.h"
- #include "clang/AST/ASTMutationListener.h"
- #include "clang/AST/CXXInheritance.h"
- #include "clang/AST/DeclCXX.h"
- #include "clang/AST/DeclObjC.h"
- #include "clang/AST/DeclTemplate.h"
- #include "clang/AST/Expr.h"
- #include "clang/AST/ExprCXX.h"
- #include "clang/AST/Mangle.h"
- #include "clang/AST/RecursiveASTVisitor.h"
- #include "clang/Basic/CharInfo.h"
- #include "clang/Basic/SourceManager.h"
- #include "clang/Basic/TargetInfo.h"
- #include "clang/Lex/Preprocessor.h"
- #include "clang/Sema/DeclSpec.h"
- #include "clang/Sema/DelayedDiagnostic.h"
- #include "clang/Sema/Initialization.h"
- #include "clang/Sema/Lookup.h"
- #include "clang/Sema/Scope.h"
- #include "clang/Sema/ScopeInfo.h"
- #include "clang/Sema/SemaInternal.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/Support/MathExtras.h"
- using namespace clang;
- using namespace sema;
- namespace AttributeLangSupport {
- enum LANG {
- C,
- Cpp,
- ObjC
- };
- } // end namespace AttributeLangSupport
- //===----------------------------------------------------------------------===//
- // Helper functions
- //===----------------------------------------------------------------------===//
- /// isFunctionOrMethod - Return true if the given decl has function
- /// type (function or function-typed variable) or an Objective-C
- /// method.
- static bool isFunctionOrMethod(const Decl *D) {
- return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D);
- }
- /// Return true if the given decl has function type (function or
- /// function-typed variable) or an Objective-C method or a block.
- static bool isFunctionOrMethodOrBlock(const Decl *D) {
- return isFunctionOrMethod(D) || isa<BlockDecl>(D);
- }
- /// Return true if the given decl has a declarator that should have
- /// been processed by Sema::GetTypeForDeclarator.
- static bool hasDeclarator(const Decl *D) {
- // In some sense, TypedefDecl really *ought* to be a DeclaratorDecl.
- return isa<DeclaratorDecl>(D) || isa<BlockDecl>(D) || isa<TypedefNameDecl>(D) ||
- isa<ObjCPropertyDecl>(D);
- }
- /// hasFunctionProto - Return true if the given decl has a argument
- /// information. This decl should have already passed
- /// isFunctionOrMethod or isFunctionOrMethodOrBlock.
- static bool hasFunctionProto(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return isa<FunctionProtoType>(FnTy);
- return isa<ObjCMethodDecl>(D) || isa<BlockDecl>(D);
- }
- /// getFunctionOrMethodNumParams - Return number of function or method
- /// parameters. It is an error to call this on a K&R function (use
- /// hasFunctionProto first).
- static unsigned getFunctionOrMethodNumParams(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return cast<FunctionProtoType>(FnTy)->getNumParams();
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->getNumParams();
- return cast<ObjCMethodDecl>(D)->param_size();
- }
- static const ParmVarDecl *getFunctionOrMethodParam(const Decl *D,
- unsigned Idx) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- return FD->getParamDecl(Idx);
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
- return MD->getParamDecl(Idx);
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->getParamDecl(Idx);
- return nullptr;
- }
- static QualType getFunctionOrMethodParamType(const Decl *D, unsigned Idx) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return cast<FunctionProtoType>(FnTy)->getParamType(Idx);
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->getParamDecl(Idx)->getType();
- return cast<ObjCMethodDecl>(D)->parameters()[Idx]->getType();
- }
- static SourceRange getFunctionOrMethodParamRange(const Decl *D, unsigned Idx) {
- if (auto *PVD = getFunctionOrMethodParam(D, Idx))
- return PVD->getSourceRange();
- return SourceRange();
- }
- static QualType getFunctionOrMethodResultType(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return FnTy->getReturnType();
- return cast<ObjCMethodDecl>(D)->getReturnType();
- }
- static SourceRange getFunctionOrMethodResultSourceRange(const Decl *D) {
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- return FD->getReturnTypeSourceRange();
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
- return MD->getReturnTypeSourceRange();
- return SourceRange();
- }
- static bool isFunctionOrMethodVariadic(const Decl *D) {
- if (const FunctionType *FnTy = D->getFunctionType())
- return cast<FunctionProtoType>(FnTy)->isVariadic();
- if (const auto *BD = dyn_cast<BlockDecl>(D))
- return BD->isVariadic();
- return cast<ObjCMethodDecl>(D)->isVariadic();
- }
- static bool isInstanceMethod(const Decl *D) {
- if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(D))
- return MethodDecl->isInstance();
- return false;
- }
- static inline bool isNSStringType(QualType T, ASTContext &Ctx) {
- const auto *PT = T->getAs<ObjCObjectPointerType>();
- if (!PT)
- return false;
- ObjCInterfaceDecl *Cls = PT->getObjectType()->getInterface();
- if (!Cls)
- return false;
- IdentifierInfo* ClsName = Cls->getIdentifier();
- // FIXME: Should we walk the chain of classes?
- return ClsName == &Ctx.Idents.get("NSString") ||
- ClsName == &Ctx.Idents.get("NSMutableString");
- }
- static inline bool isCFStringType(QualType T, ASTContext &Ctx) {
- const auto *PT = T->getAs<PointerType>();
- if (!PT)
- return false;
- const auto *RT = PT->getPointeeType()->getAs<RecordType>();
- if (!RT)
- return false;
- const RecordDecl *RD = RT->getDecl();
- if (RD->getTagKind() != TTK_Struct)
- return false;
- return RD->getIdentifier() == &Ctx.Idents.get("__CFString");
- }
- static unsigned getNumAttributeArgs(const ParsedAttr &AL) {
- // FIXME: Include the type in the argument list.
- return AL.getNumArgs() + AL.hasParsedType();
- }
- template <typename Compare>
- static bool checkAttributeNumArgsImpl(Sema &S, const ParsedAttr &AL,
- unsigned Num, unsigned Diag,
- Compare Comp) {
- if (Comp(getNumAttributeArgs(AL), Num)) {
- S.Diag(AL.getLoc(), Diag) << AL << Num;
- return false;
- }
- return true;
- }
- /// Check if the attribute has exactly as many args as Num. May
- /// output an error.
- static bool checkAttributeNumArgs(Sema &S, const ParsedAttr &AL, unsigned Num) {
- return checkAttributeNumArgsImpl(S, AL, Num,
- diag::err_attribute_wrong_number_arguments,
- std::not_equal_to<unsigned>());
- }
- /// Check if the attribute has at least as many args as Num. May
- /// output an error.
- static bool checkAttributeAtLeastNumArgs(Sema &S, const ParsedAttr &AL,
- unsigned Num) {
- return checkAttributeNumArgsImpl(S, AL, Num,
- diag::err_attribute_too_few_arguments,
- std::less<unsigned>());
- }
- /// Check if the attribute has at most as many args as Num. May
- /// output an error.
- static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL,
- unsigned Num) {
- return checkAttributeNumArgsImpl(S, AL, Num,
- diag::err_attribute_too_many_arguments,
- std::greater<unsigned>());
- }
- /// A helper function to provide Attribute Location for the Attr types
- /// AND the ParsedAttr.
- template <typename AttrInfo>
- static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value,
- SourceLocation>::type
- getAttrLoc(const AttrInfo &AL) {
- return AL.getLocation();
- }
- static SourceLocation getAttrLoc(const ParsedAttr &AL) { return AL.getLoc(); }
- /// If Expr is a valid integer constant, get the value of the integer
- /// expression and return success or failure. May output an error.
- ///
- /// Negative argument is implicitly converted to unsigned, unless
- /// \p StrictlyUnsigned is true.
- template <typename AttrInfo>
- static bool checkUInt32Argument(Sema &S, const AttrInfo &AI, const Expr *Expr,
- uint32_t &Val, unsigned Idx = UINT_MAX,
- bool StrictlyUnsigned = false) {
- llvm::APSInt I(32);
- if (Expr->isTypeDependent() || Expr->isValueDependent() ||
- !Expr->isIntegerConstantExpr(I, S.Context)) {
- if (Idx != UINT_MAX)
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
- << &AI << Idx << AANT_ArgumentIntegerConstant
- << Expr->getSourceRange();
- else
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_type)
- << &AI << AANT_ArgumentIntegerConstant << Expr->getSourceRange();
- return false;
- }
- if (!I.isIntN(32)) {
- S.Diag(Expr->getExprLoc(), diag::err_ice_too_large)
- << I.toString(10, false) << 32 << /* Unsigned */ 1;
- return false;
- }
- if (StrictlyUnsigned && I.isSigned() && I.isNegative()) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_requires_positive_integer)
- << &AI << /*non-negative*/ 1;
- return false;
- }
- Val = (uint32_t)I.getZExtValue();
- return true;
- }
- /// Wrapper around checkUInt32Argument, with an extra check to be sure
- /// that the result will fit into a regular (signed) int. All args have the same
- /// purpose as they do in checkUInt32Argument.
- template <typename AttrInfo>
- static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Expr,
- int &Val, unsigned Idx = UINT_MAX) {
- uint32_t UVal;
- if (!checkUInt32Argument(S, AI, Expr, UVal, Idx))
- return false;
- if (UVal > (uint32_t)std::numeric_limits<int>::max()) {
- llvm::APSInt I(32); // for toString
- I = UVal;
- S.Diag(Expr->getExprLoc(), diag::err_ice_too_large)
- << I.toString(10, false) << 32 << /* Unsigned */ 0;
- return false;
- }
- Val = UVal;
- return true;
- }
- /// Diagnose mutually exclusive attributes when present on a given
- /// declaration. Returns true if diagnosed.
- template <typename AttrTy>
- static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (const auto *A = D->getAttr<AttrTy>()) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A;
- S.Diag(A->getLocation(), diag::note_conflicting_attribute);
- return true;
- }
- return false;
- }
- template <typename AttrTy>
- static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) {
- if (const auto *A = D->getAttr<AttrTy>()) {
- S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL
- << A;
- S.Diag(A->getLocation(), diag::note_conflicting_attribute);
- return true;
- }
- return false;
- }
- /// Check if IdxExpr is a valid parameter index for a function or
- /// instance method D. May output an error.
- ///
- /// \returns true if IdxExpr is a valid index.
- template <typename AttrInfo>
- static bool checkFunctionOrMethodParameterIndex(
- Sema &S, const Decl *D, const AttrInfo &AI, unsigned AttrArgNum,
- const Expr *IdxExpr, ParamIdx &Idx, bool CanIndexImplicitThis = false) {
- assert(isFunctionOrMethodOrBlock(D));
- // In C++ the implicit 'this' function parameter also counts.
- // Parameters are counted from one.
- bool HP = hasFunctionProto(D);
- bool HasImplicitThisParam = isInstanceMethod(D);
- bool IV = HP && isFunctionOrMethodVariadic(D);
- unsigned NumParams =
- (HP ? getFunctionOrMethodNumParams(D) : 0) + HasImplicitThisParam;
- llvm::APSInt IdxInt;
- if (IdxExpr->isTypeDependent() || IdxExpr->isValueDependent() ||
- !IdxExpr->isIntegerConstantExpr(IdxInt, S.Context)) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_n_type)
- << &AI << AttrArgNum << AANT_ArgumentIntegerConstant
- << IdxExpr->getSourceRange();
- return false;
- }
- unsigned IdxSource = IdxInt.getLimitedValue(UINT_MAX);
- if (IdxSource < 1 || (!IV && IdxSource > NumParams)) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_argument_out_of_bounds)
- << &AI << AttrArgNum << IdxExpr->getSourceRange();
- return false;
- }
- if (HasImplicitThisParam && !CanIndexImplicitThis) {
- if (IdxSource == 1) {
- S.Diag(getAttrLoc(AI), diag::err_attribute_invalid_implicit_this_argument)
- << &AI << IdxExpr->getSourceRange();
- return false;
- }
- }
- Idx = ParamIdx(IdxSource, D);
- return true;
- }
- /// Check if the argument \p ArgNum of \p Attr is a ASCII string literal.
- /// If not emit an error and return false. If the argument is an identifier it
- /// will emit an error with a fixit hint and treat it as if it was a string
- /// literal.
- bool Sema::checkStringLiteralArgumentAttr(const ParsedAttr &AL, unsigned ArgNum,
- StringRef &Str,
- SourceLocation *ArgLocation) {
- // Look for identifiers. If we have one emit a hint to fix it to a literal.
- if (AL.isArgIdent(ArgNum)) {
- IdentifierLoc *Loc = AL.getArgAsIdent(ArgNum);
- Diag(Loc->Loc, diag::err_attribute_argument_type)
- << AL << AANT_ArgumentString
- << FixItHint::CreateInsertion(Loc->Loc, "\"")
- << FixItHint::CreateInsertion(getLocForEndOfToken(Loc->Loc), "\"");
- Str = Loc->Ident->getName();
- if (ArgLocation)
- *ArgLocation = Loc->Loc;
- return true;
- }
- // Now check for an actual string literal.
- Expr *ArgExpr = AL.getArgAsExpr(ArgNum);
- const auto *Literal = dyn_cast<StringLiteral>(ArgExpr->IgnoreParenCasts());
- if (ArgLocation)
- *ArgLocation = ArgExpr->getBeginLoc();
- if (!Literal || !Literal->isAscii()) {
- Diag(ArgExpr->getBeginLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentString;
- return false;
- }
- Str = Literal->getString();
- return true;
- }
- /// Applies the given attribute to the Decl without performing any
- /// additional semantic checking.
- template <typename AttrType>
- static void handleSimpleAttribute(Sema &S, Decl *D,
- const AttributeCommonInfo &CI) {
- D->addAttr(::new (S.Context) AttrType(S.Context, CI));
- }
- template <typename... DiagnosticArgs>
- static const Sema::SemaDiagnosticBuilder&
- appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr) {
- return Bldr;
- }
- template <typename T, typename... DiagnosticArgs>
- static const Sema::SemaDiagnosticBuilder&
- appendDiagnostics(const Sema::SemaDiagnosticBuilder &Bldr, T &&ExtraArg,
- DiagnosticArgs &&... ExtraArgs) {
- return appendDiagnostics(Bldr << std::forward<T>(ExtraArg),
- std::forward<DiagnosticArgs>(ExtraArgs)...);
- }
- /// Add an attribute {@code AttrType} to declaration {@code D}, provided that
- /// {@code PassesCheck} is true.
- /// Otherwise, emit diagnostic {@code DiagID}, passing in all parameters
- /// specified in {@code ExtraArgs}.
- template <typename AttrType, typename... DiagnosticArgs>
- static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D,
- const AttributeCommonInfo &CI,
- bool PassesCheck, unsigned DiagID,
- DiagnosticArgs &&... ExtraArgs) {
- if (!PassesCheck) {
- Sema::SemaDiagnosticBuilder DB = S.Diag(D->getBeginLoc(), DiagID);
- appendDiagnostics(DB, std::forward<DiagnosticArgs>(ExtraArgs)...);
- return;
- }
- handleSimpleAttribute<AttrType>(S, D, CI);
- }
- template <typename AttrType>
- static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- handleSimpleAttribute<AttrType>(S, D, AL);
- }
- /// Applies the given attribute to the Decl so long as the Decl doesn't
- /// already have one of the given incompatible attributes.
- template <typename AttrType, typename IncompatibleAttrType,
- typename... IncompatibleAttrTypes>
- static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL))
- return;
- handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D,
- AL);
- }
- /// Check if the passed-in expression is of type int or bool.
- static bool isIntOrBool(Expr *Exp) {
- QualType QT = Exp->getType();
- return QT->isBooleanType() || QT->isIntegerType();
- }
- // Check to see if the type is a smart pointer of some kind. We assume
- // it's a smart pointer if it defines both operator-> and operator*.
- static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) {
- auto IsOverloadedOperatorPresent = [&S](const RecordDecl *Record,
- OverloadedOperatorKind Op) {
- DeclContextLookupResult Result =
- Record->lookup(S.Context.DeclarationNames.getCXXOperatorName(Op));
- return !Result.empty();
- };
- const RecordDecl *Record = RT->getDecl();
- bool foundStarOperator = IsOverloadedOperatorPresent(Record, OO_Star);
- bool foundArrowOperator = IsOverloadedOperatorPresent(Record, OO_Arrow);
- if (foundStarOperator && foundArrowOperator)
- return true;
- const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record);
- if (!CXXRecord)
- return false;
- for (auto BaseSpecifier : CXXRecord->bases()) {
- if (!foundStarOperator)
- foundStarOperator = IsOverloadedOperatorPresent(
- BaseSpecifier.getType()->getAsRecordDecl(), OO_Star);
- if (!foundArrowOperator)
- foundArrowOperator = IsOverloadedOperatorPresent(
- BaseSpecifier.getType()->getAsRecordDecl(), OO_Arrow);
- }
- if (foundStarOperator && foundArrowOperator)
- return true;
- return false;
- }
- /// Check if passed in Decl is a pointer type.
- /// Note that this function may produce an error message.
- /// \return true if the Decl is a pointer type; false otherwise
- static bool threadSafetyCheckIsPointer(Sema &S, const Decl *D,
- const ParsedAttr &AL) {
- const auto *VD = cast<ValueDecl>(D);
- QualType QT = VD->getType();
- if (QT->isAnyPointerType())
- return true;
- if (const auto *RT = QT->getAs<RecordType>()) {
- // If it's an incomplete type, it could be a smart pointer; skip it.
- // (We don't want to force template instantiation if we can avoid it,
- // since that would alter the order in which templates are instantiated.)
- if (RT->isIncompleteType())
- return true;
- if (threadSafetyCheckIsSmartPointer(S, RT))
- return true;
- }
- S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_pointer) << AL << QT;
- return false;
- }
- /// Checks that the passed in QualType either is of RecordType or points
- /// to RecordType. Returns the relevant RecordType, null if it does not exit.
- static const RecordType *getRecordType(QualType QT) {
- if (const auto *RT = QT->getAs<RecordType>())
- return RT;
- // Now check if we point to record type.
- if (const auto *PT = QT->getAs<PointerType>())
- return PT->getPointeeType()->getAs<RecordType>();
- return nullptr;
- }
- template <typename AttrType>
- static bool checkRecordDeclForAttr(const RecordDecl *RD) {
- // Check if the record itself has the attribute.
- if (RD->hasAttr<AttrType>())
- return true;
- // Else check if any base classes have the attribute.
- if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) {
- CXXBasePaths BPaths(false, false);
- if (CRD->lookupInBases(
- [](const CXXBaseSpecifier *BS, CXXBasePath &) {
- const auto &Ty = *BS->getType();
- // If it's type-dependent, we assume it could have the attribute.
- if (Ty.isDependentType())
- return true;
- return Ty.castAs<RecordType>()->getDecl()->hasAttr<AttrType>();
- },
- BPaths, true))
- return true;
- }
- return false;
- }
- static bool checkRecordTypeForCapability(Sema &S, QualType Ty) {
- const RecordType *RT = getRecordType(Ty);
- if (!RT)
- return false;
- // Don't check for the capability if the class hasn't been defined yet.
- if (RT->isIncompleteType())
- return true;
- // Allow smart pointers to be used as capability objects.
- // FIXME -- Check the type that the smart pointer points to.
- if (threadSafetyCheckIsSmartPointer(S, RT))
- return true;
- return checkRecordDeclForAttr<CapabilityAttr>(RT->getDecl());
- }
- static bool checkTypedefTypeForCapability(QualType Ty) {
- const auto *TD = Ty->getAs<TypedefType>();
- if (!TD)
- return false;
- TypedefNameDecl *TN = TD->getDecl();
- if (!TN)
- return false;
- return TN->hasAttr<CapabilityAttr>();
- }
- static bool typeHasCapability(Sema &S, QualType Ty) {
- if (checkTypedefTypeForCapability(Ty))
- return true;
- if (checkRecordTypeForCapability(S, Ty))
- return true;
- return false;
- }
- static bool isCapabilityExpr(Sema &S, const Expr *Ex) {
- // Capability expressions are simple expressions involving the boolean logic
- // operators &&, || or !, a simple DeclRefExpr, CastExpr or a ParenExpr. Once
- // a DeclRefExpr is found, its type should be checked to determine whether it
- // is a capability or not.
- if (const auto *E = dyn_cast<CastExpr>(Ex))
- return isCapabilityExpr(S, E->getSubExpr());
- else if (const auto *E = dyn_cast<ParenExpr>(Ex))
- return isCapabilityExpr(S, E->getSubExpr());
- else if (const auto *E = dyn_cast<UnaryOperator>(Ex)) {
- if (E->getOpcode() == UO_LNot || E->getOpcode() == UO_AddrOf ||
- E->getOpcode() == UO_Deref)
- return isCapabilityExpr(S, E->getSubExpr());
- return false;
- } else if (const auto *E = dyn_cast<BinaryOperator>(Ex)) {
- if (E->getOpcode() == BO_LAnd || E->getOpcode() == BO_LOr)
- return isCapabilityExpr(S, E->getLHS()) &&
- isCapabilityExpr(S, E->getRHS());
- return false;
- }
- return typeHasCapability(S, Ex->getType());
- }
- /// Checks that all attribute arguments, starting from Sidx, resolve to
- /// a capability object.
- /// \param Sidx The attribute argument index to start checking with.
- /// \param ParamIdxOk Whether an argument can be indexing into a function
- /// parameter list.
- static void checkAttrArgsAreCapabilityObjs(Sema &S, Decl *D,
- const ParsedAttr &AL,
- SmallVectorImpl<Expr *> &Args,
- unsigned Sidx = 0,
- bool ParamIdxOk = false) {
- if (Sidx == AL.getNumArgs()) {
- // If we don't have any capability arguments, the attribute implicitly
- // refers to 'this'. So we need to make sure that 'this' exists, i.e. we're
- // a non-static method, and that the class is a (scoped) capability.
- const auto *MD = dyn_cast<const CXXMethodDecl>(D);
- if (MD && !MD->isStatic()) {
- const CXXRecordDecl *RD = MD->getParent();
- // FIXME -- need to check this again on template instantiation
- if (!checkRecordDeclForAttr<CapabilityAttr>(RD) &&
- !checkRecordDeclForAttr<ScopedLockableAttr>(RD))
- S.Diag(AL.getLoc(),
- diag::warn_thread_attribute_not_on_capability_member)
- << AL << MD->getParent();
- } else {
- S.Diag(AL.getLoc(), diag::warn_thread_attribute_not_on_non_static_member)
- << AL;
- }
- }
- for (unsigned Idx = Sidx; Idx < AL.getNumArgs(); ++Idx) {
- Expr *ArgExp = AL.getArgAsExpr(Idx);
- if (ArgExp->isTypeDependent()) {
- // FIXME -- need to check this again on template instantiation
- Args.push_back(ArgExp);
- continue;
- }
- if (const auto *StrLit = dyn_cast<StringLiteral>(ArgExp)) {
- if (StrLit->getLength() == 0 ||
- (StrLit->isAscii() && StrLit->getString() == StringRef("*"))) {
- // Pass empty strings to the analyzer without warnings.
- // Treat "*" as the universal lock.
- Args.push_back(ArgExp);
- continue;
- }
- // We allow constant strings to be used as a placeholder for expressions
- // that are not valid C++ syntax, but warn that they are ignored.
- S.Diag(AL.getLoc(), diag::warn_thread_attribute_ignored) << AL;
- Args.push_back(ArgExp);
- continue;
- }
- QualType ArgTy = ArgExp->getType();
- // A pointer to member expression of the form &MyClass::mu is treated
- // specially -- we need to look at the type of the member.
- if (const auto *UOp = dyn_cast<UnaryOperator>(ArgExp))
- if (UOp->getOpcode() == UO_AddrOf)
- if (const auto *DRE = dyn_cast<DeclRefExpr>(UOp->getSubExpr()))
- if (DRE->getDecl()->isCXXInstanceMember())
- ArgTy = DRE->getDecl()->getType();
- // First see if we can just cast to record type, or pointer to record type.
- const RecordType *RT = getRecordType(ArgTy);
- // Now check if we index into a record type function param.
- if(!RT && ParamIdxOk) {
- const auto *FD = dyn_cast<FunctionDecl>(D);
- const auto *IL = dyn_cast<IntegerLiteral>(ArgExp);
- if(FD && IL) {
- unsigned int NumParams = FD->getNumParams();
- llvm::APInt ArgValue = IL->getValue();
- uint64_t ParamIdxFromOne = ArgValue.getZExtValue();
- uint64_t ParamIdxFromZero = ParamIdxFromOne - 1;
- if (!ArgValue.isStrictlyPositive() || ParamIdxFromOne > NumParams) {
- S.Diag(AL.getLoc(),
- diag::err_attribute_argument_out_of_bounds_extra_info)
- << AL << Idx + 1 << NumParams;
- continue;
- }
- ArgTy = FD->getParamDecl(ParamIdxFromZero)->getType();
- }
- }
- // If the type does not have a capability, see if the components of the
- // expression have capabilities. This allows for writing C code where the
- // capability may be on the type, and the expression is a capability
- // boolean logic expression. Eg) requires_capability(A || B && !C)
- if (!typeHasCapability(S, ArgTy) && !isCapabilityExpr(S, ArgExp))
- S.Diag(AL.getLoc(), diag::warn_thread_attribute_argument_not_lockable)
- << AL << ArgTy;
- Args.push_back(ArgExp);
- }
- }
- //===----------------------------------------------------------------------===//
- // Attribute Implementations
- //===----------------------------------------------------------------------===//
- static void handlePtGuardedVarAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!threadSafetyCheckIsPointer(S, D, AL))
- return;
- D->addAttr(::new (S.Context) PtGuardedVarAttr(S.Context, AL));
- }
- static bool checkGuardedByAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
- Expr *&Arg) {
- SmallVector<Expr *, 1> Args;
- // check that all arguments are lockable objects
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
- unsigned Size = Args.size();
- if (Size != 1)
- return false;
- Arg = Args[0];
- return true;
- }
- static void handleGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- Expr *Arg = nullptr;
- if (!checkGuardedByAttrCommon(S, D, AL, Arg))
- return;
- D->addAttr(::new (S.Context) GuardedByAttr(S.Context, AL, Arg));
- }
- static void handlePtGuardedByAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- Expr *Arg = nullptr;
- if (!checkGuardedByAttrCommon(S, D, AL, Arg))
- return;
- if (!threadSafetyCheckIsPointer(S, D, AL))
- return;
- D->addAttr(::new (S.Context) PtGuardedByAttr(S.Context, AL, Arg));
- }
- static bool checkAcquireOrderAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
- SmallVectorImpl<Expr *> &Args) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return false;
- // Check that this attribute only applies to lockable types.
- QualType QT = cast<ValueDecl>(D)->getType();
- if (!QT->isDependentType() && !typeHasCapability(S, QT)) {
- S.Diag(AL.getLoc(), diag::warn_thread_attribute_decl_not_lockable) << AL;
- return false;
- }
- // Check that all arguments are lockable objects.
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
- if (Args.empty())
- return false;
- return true;
- }
- static void handleAcquiredAfterAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- SmallVector<Expr *, 1> Args;
- if (!checkAcquireOrderAttrCommon(S, D, AL, Args))
- return;
- Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context)
- AcquiredAfterAttr(S.Context, AL, StartArg, Args.size()));
- }
- static void handleAcquiredBeforeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- SmallVector<Expr *, 1> Args;
- if (!checkAcquireOrderAttrCommon(S, D, AL, Args))
- return;
- Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context)
- AcquiredBeforeAttr(S.Context, AL, StartArg, Args.size()));
- }
- static bool checkLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
- SmallVectorImpl<Expr *> &Args) {
- // zero or more arguments ok
- // check that all arguments are lockable objects
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, /*ParamIdxOk=*/true);
- return true;
- }
- static void handleAssertSharedLockAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- SmallVector<Expr *, 1> Args;
- if (!checkLockFunAttrCommon(S, D, AL, Args))
- return;
- unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? nullptr : &Args[0];
- D->addAttr(::new (S.Context)
- AssertSharedLockAttr(S.Context, AL, StartArg, Size));
- }
- static void handleAssertExclusiveLockAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- SmallVector<Expr *, 1> Args;
- if (!checkLockFunAttrCommon(S, D, AL, Args))
- return;
- unsigned Size = Args.size();
- Expr **StartArg = Size == 0 ? nullptr : &Args[0];
- D->addAttr(::new (S.Context)
- AssertExclusiveLockAttr(S.Context, AL, StartArg, Size));
- }
- /// Checks to be sure that the given parameter number is in bounds, and
- /// is an integral type. Will emit appropriate diagnostics if this returns
- /// false.
- ///
- /// AttrArgNo is used to actually retrieve the argument, so it's base-0.
- template <typename AttrInfo>
- static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD,
- const AttrInfo &AI, unsigned AttrArgNo) {
- assert(AI.isArgExpr(AttrArgNo) && "Expected expression argument");
- Expr *AttrArg = AI.getArgAsExpr(AttrArgNo);
- ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, FD, AI, AttrArgNo + 1, AttrArg,
- Idx))
- return false;
- const ParmVarDecl *Param = FD->getParamDecl(Idx.getASTIndex());
- if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) {
- SourceLocation SrcLoc = AttrArg->getBeginLoc();
- S.Diag(SrcLoc, diag::err_attribute_integers_only)
- << AI << Param->getSourceRange();
- return false;
- }
- return true;
- }
- static void handleAllocSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1) ||
- !checkAttributeAtMostNumArgs(S, AL, 2))
- return;
- const auto *FD = cast<FunctionDecl>(D);
- if (!FD->getReturnType()->isPointerType()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only) << AL;
- return;
- }
- const Expr *SizeExpr = AL.getArgAsExpr(0);
- int SizeArgNoVal;
- // Parameter indices are 1-indexed, hence Index=1
- if (!checkPositiveIntArgument(S, AL, SizeExpr, SizeArgNoVal, /*Idx=*/1))
- return;
- if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/0))
- return;
- ParamIdx SizeArgNo(SizeArgNoVal, D);
- ParamIdx NumberArgNo;
- if (AL.getNumArgs() == 2) {
- const Expr *NumberExpr = AL.getArgAsExpr(1);
- int Val;
- // Parameter indices are 1-based, hence Index=2
- if (!checkPositiveIntArgument(S, AL, NumberExpr, Val, /*Idx=*/2))
- return;
- if (!checkParamIsIntegerType(S, FD, AL, /*AttrArgNo=*/1))
- return;
- NumberArgNo = ParamIdx(Val, D);
- }
- D->addAttr(::new (S.Context)
- AllocSizeAttr(S.Context, AL, SizeArgNo, NumberArgNo));
- }
- static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const ParsedAttr &AL,
- SmallVectorImpl<Expr *> &Args) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return false;
- if (!isIntOrBool(AL.getArgAsExpr(0))) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIntOrBool;
- return false;
- }
- // check that all arguments are lockable objects
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 1);
- return true;
- }
- static void handleSharedTrylockFunctionAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- SmallVector<Expr*, 2> Args;
- if (!checkTryLockFunAttrCommon(S, D, AL, Args))
- return;
- D->addAttr(::new (S.Context) SharedTrylockFunctionAttr(
- S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
- }
- static void handleExclusiveTrylockFunctionAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- SmallVector<Expr*, 2> Args;
- if (!checkTryLockFunAttrCommon(S, D, AL, Args))
- return;
- D->addAttr(::new (S.Context) ExclusiveTrylockFunctionAttr(
- S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
- }
- static void handleLockReturnedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // check that the argument is lockable object
- SmallVector<Expr*, 1> Args;
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
- unsigned Size = Args.size();
- if (Size == 0)
- return;
- D->addAttr(::new (S.Context) LockReturnedAttr(S.Context, AL, Args[0]));
- }
- static void handleLocksExcludedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- // check that all arguments are lockable objects
- SmallVector<Expr*, 1> Args;
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
- unsigned Size = Args.size();
- if (Size == 0)
- return;
- Expr **StartArg = &Args[0];
- D->addAttr(::new (S.Context)
- LocksExcludedAttr(S.Context, AL, StartArg, Size));
- }
- static bool checkFunctionConditionAttr(Sema &S, Decl *D, const ParsedAttr &AL,
- Expr *&Cond, StringRef &Msg) {
- Cond = AL.getArgAsExpr(0);
- if (!Cond->isTypeDependent()) {
- ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
- if (Converted.isInvalid())
- return false;
- Cond = Converted.get();
- }
- if (!S.checkStringLiteralArgumentAttr(AL, 1, Msg))
- return false;
- if (Msg.empty())
- Msg = "<no message provided>";
- SmallVector<PartialDiagnosticAt, 8> Diags;
- if (isa<FunctionDecl>(D) && !Cond->isValueDependent() &&
- !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D),
- Diags)) {
- S.Diag(AL.getLoc(), diag::err_attr_cond_never_constant_expr) << AL;
- for (const PartialDiagnosticAt &PDiag : Diags)
- S.Diag(PDiag.first, PDiag.second);
- return false;
- }
- return true;
- }
- static void handleEnableIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.Diag(AL.getLoc(), diag::ext_clang_enable_if);
- Expr *Cond;
- StringRef Msg;
- if (checkFunctionConditionAttr(S, D, AL, Cond, Msg))
- D->addAttr(::new (S.Context) EnableIfAttr(S.Context, AL, Cond, Msg));
- }
- namespace {
- /// Determines if a given Expr references any of the given function's
- /// ParmVarDecls, or the function's implicit `this` parameter (if applicable).
- class ArgumentDependenceChecker
- : public RecursiveASTVisitor<ArgumentDependenceChecker> {
- #ifndef NDEBUG
- const CXXRecordDecl *ClassType;
- #endif
- llvm::SmallPtrSet<const ParmVarDecl *, 16> Parms;
- bool Result;
- public:
- ArgumentDependenceChecker(const FunctionDecl *FD) {
- #ifndef NDEBUG
- if (const auto *MD = dyn_cast<CXXMethodDecl>(FD))
- ClassType = MD->getParent();
- else
- ClassType = nullptr;
- #endif
- Parms.insert(FD->param_begin(), FD->param_end());
- }
- bool referencesArgs(Expr *E) {
- Result = false;
- TraverseStmt(E);
- return Result;
- }
- bool VisitCXXThisExpr(CXXThisExpr *E) {
- assert(E->getType()->getPointeeCXXRecordDecl() == ClassType &&
- "`this` doesn't refer to the enclosing class?");
- Result = true;
- return false;
- }
- bool VisitDeclRefExpr(DeclRefExpr *DRE) {
- if (const auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
- if (Parms.count(PVD)) {
- Result = true;
- return false;
- }
- return true;
- }
- };
- }
- static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.Diag(AL.getLoc(), diag::ext_clang_diagnose_if);
- Expr *Cond;
- StringRef Msg;
- if (!checkFunctionConditionAttr(S, D, AL, Cond, Msg))
- return;
- StringRef DiagTypeStr;
- if (!S.checkStringLiteralArgumentAttr(AL, 2, DiagTypeStr))
- return;
- DiagnoseIfAttr::DiagnosticType DiagType;
- if (!DiagnoseIfAttr::ConvertStrToDiagnosticType(DiagTypeStr, DiagType)) {
- S.Diag(AL.getArgAsExpr(2)->getBeginLoc(),
- diag::err_diagnose_if_invalid_diagnostic_type);
- return;
- }
- bool ArgDependent = false;
- if (const auto *FD = dyn_cast<FunctionDecl>(D))
- ArgDependent = ArgumentDependenceChecker(FD).referencesArgs(Cond);
- D->addAttr(::new (S.Context) DiagnoseIfAttr(
- S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D)));
- }
- static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (D->hasAttr<PassObjectSizeAttr>()) {
- S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL;
- return;
- }
- Expr *E = AL.getArgAsExpr(0);
- uint32_t Type;
- if (!checkUInt32Argument(S, AL, E, Type, /*Idx=*/1))
- return;
- // pass_object_size's argument is passed in as the second argument of
- // __builtin_object_size. So, it has the same constraints as that second
- // argument; namely, it must be in the range [0, 3].
- if (Type > 3) {
- S.Diag(E->getBeginLoc(), diag::err_attribute_argument_out_of_range)
- << AL << 0 << 3 << E->getSourceRange();
- return;
- }
- // pass_object_size is only supported on constant pointer parameters; as a
- // kindness to users, we allow the parameter to be non-const for declarations.
- // At this point, we have no clue if `D` belongs to a function declaration or
- // definition, so we defer the constness check until later.
- if (!cast<ParmVarDecl>(D)->getType()->isPointerType()) {
- S.Diag(D->getBeginLoc(), diag::err_attribute_pointers_only) << AL << 1;
- return;
- }
- D->addAttr(::new (S.Context) PassObjectSizeAttr(S.Context, AL, (int)Type));
- }
- static void handleConsumableAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- ConsumableAttr::ConsumedState DefaultState;
- if (AL.isArgIdent(0)) {
- IdentifierLoc *IL = AL.getArgAsIdent(0);
- if (!ConsumableAttr::ConvertStrToConsumedState(IL->Ident->getName(),
- DefaultState)) {
- S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL
- << IL->Ident;
- return;
- }
- } else {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
- D->addAttr(::new (S.Context) ConsumableAttr(S.Context, AL, DefaultState));
- }
- static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
- const ParsedAttr &AL) {
- QualType ThisType = MD->getThisType()->getPointeeType();
- if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) {
- if (!RD->hasAttr<ConsumableAttr>()) {
- S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) <<
- RD->getNameAsString();
- return false;
- }
- }
- return true;
- }
- static void handleCallableWhenAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL))
- return;
- SmallVector<CallableWhenAttr::ConsumedState, 3> States;
- for (unsigned ArgIndex = 0; ArgIndex < AL.getNumArgs(); ++ArgIndex) {
- CallableWhenAttr::ConsumedState CallableState;
- StringRef StateString;
- SourceLocation Loc;
- if (AL.isArgIdent(ArgIndex)) {
- IdentifierLoc *Ident = AL.getArgAsIdent(ArgIndex);
- StateString = Ident->Ident->getName();
- Loc = Ident->Loc;
- } else {
- if (!S.checkStringLiteralArgumentAttr(AL, ArgIndex, StateString, &Loc))
- return;
- }
- if (!CallableWhenAttr::ConvertStrToConsumedState(StateString,
- CallableState)) {
- S.Diag(Loc, diag::warn_attribute_type_not_supported) << AL << StateString;
- return;
- }
- States.push_back(CallableState);
- }
- D->addAttr(::new (S.Context)
- CallableWhenAttr(S.Context, AL, States.data(), States.size()));
- }
- static void handleParamTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- ParamTypestateAttr::ConsumedState ParamState;
- if (AL.isArgIdent(0)) {
- IdentifierLoc *Ident = AL.getArgAsIdent(0);
- StringRef StateString = Ident->Ident->getName();
- if (!ParamTypestateAttr::ConvertStrToConsumedState(StateString,
- ParamState)) {
- S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported)
- << AL << StateString;
- return;
- }
- } else {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
- // FIXME: This check is currently being done in the analysis. It can be
- // enabled here only after the parser propagates attributes at
- // template specialization definition, not declaration.
- //QualType ReturnType = cast<ParmVarDecl>(D)->getType();
- //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
- //
- //if (!RD || !RD->hasAttr<ConsumableAttr>()) {
- // S.Diag(AL.getLoc(), diag::warn_return_state_for_unconsumable_type) <<
- // ReturnType.getAsString();
- // return;
- //}
- D->addAttr(::new (S.Context) ParamTypestateAttr(S.Context, AL, ParamState));
- }
- static void handleReturnTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- ReturnTypestateAttr::ConsumedState ReturnState;
- if (AL.isArgIdent(0)) {
- IdentifierLoc *IL = AL.getArgAsIdent(0);
- if (!ReturnTypestateAttr::ConvertStrToConsumedState(IL->Ident->getName(),
- ReturnState)) {
- S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL
- << IL->Ident;
- return;
- }
- } else {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
- // FIXME: This check is currently being done in the analysis. It can be
- // enabled here only after the parser propagates attributes at
- // template specialization definition, not declaration.
- //QualType ReturnType;
- //
- //if (const ParmVarDecl *Param = dyn_cast<ParmVarDecl>(D)) {
- // ReturnType = Param->getType();
- //
- //} else if (const CXXConstructorDecl *Constructor =
- // dyn_cast<CXXConstructorDecl>(D)) {
- // ReturnType = Constructor->getThisType()->getPointeeType();
- //
- //} else {
- //
- // ReturnType = cast<FunctionDecl>(D)->getCallResultType();
- //}
- //
- //const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
- //
- //if (!RD || !RD->hasAttr<ConsumableAttr>()) {
- // S.Diag(Attr.getLoc(), diag::warn_return_state_for_unconsumable_type) <<
- // ReturnType.getAsString();
- // return;
- //}
- D->addAttr(::new (S.Context) ReturnTypestateAttr(S.Context, AL, ReturnState));
- }
- static void handleSetTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL))
- return;
- SetTypestateAttr::ConsumedState NewState;
- if (AL.isArgIdent(0)) {
- IdentifierLoc *Ident = AL.getArgAsIdent(0);
- StringRef Param = Ident->Ident->getName();
- if (!SetTypestateAttr::ConvertStrToConsumedState(Param, NewState)) {
- S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL
- << Param;
- return;
- }
- } else {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
- D->addAttr(::new (S.Context) SetTypestateAttr(S.Context, AL, NewState));
- }
- static void handleTestTypestateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), AL))
- return;
- TestTypestateAttr::ConsumedState TestState;
- if (AL.isArgIdent(0)) {
- IdentifierLoc *Ident = AL.getArgAsIdent(0);
- StringRef Param = Ident->Ident->getName();
- if (!TestTypestateAttr::ConvertStrToConsumedState(Param, TestState)) {
- S.Diag(Ident->Loc, diag::warn_attribute_type_not_supported) << AL
- << Param;
- return;
- }
- } else {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
- D->addAttr(::new (S.Context) TestTypestateAttr(S.Context, AL, TestState));
- }
- static void handleExtVectorTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Remember this typedef decl, we will need it later for diagnostics.
- S.ExtVectorDecls.push_back(cast<TypedefNameDecl>(D));
- }
- static void handlePackedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (auto *TD = dyn_cast<TagDecl>(D))
- TD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
- else if (auto *FD = dyn_cast<FieldDecl>(D)) {
- bool BitfieldByteAligned = (!FD->getType()->isDependentType() &&
- !FD->getType()->isIncompleteType() &&
- FD->isBitField() &&
- S.Context.getTypeAlign(FD->getType()) <= 8);
- if (S.getASTContext().getTargetInfo().getTriple().isPS4()) {
- if (BitfieldByteAligned)
- // The PS4 target needs to maintain ABI backwards compatibility.
- S.Diag(AL.getLoc(), diag::warn_attribute_ignored_for_field_of_type)
- << AL << FD->getType();
- else
- FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
- } else {
- // Report warning about changed offset in the newer compiler versions.
- if (BitfieldByteAligned)
- S.Diag(AL.getLoc(), diag::warn_attribute_packed_for_bitfield);
- FD->addAttr(::new (S.Context) PackedAttr(S.Context, AL));
- }
- } else
- S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
- }
- static bool checkIBOutletCommon(Sema &S, Decl *D, const ParsedAttr &AL) {
- // The IBOutlet/IBOutletCollection attributes only apply to instance
- // variables or properties of Objective-C classes. The outlet must also
- // have an object reference type.
- if (const auto *VD = dyn_cast<ObjCIvarDecl>(D)) {
- if (!VD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type)
- << AL << VD->getType() << 0;
- return false;
- }
- }
- else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
- if (!PD->getType()->getAs<ObjCObjectPointerType>()) {
- S.Diag(AL.getLoc(), diag::warn_iboutlet_object_type)
- << AL << PD->getType() << 1;
- return false;
- }
- }
- else {
- S.Diag(AL.getLoc(), diag::warn_attribute_iboutlet) << AL;
- return false;
- }
- return true;
- }
- static void handleIBOutlet(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkIBOutletCommon(S, D, AL))
- return;
- D->addAttr(::new (S.Context) IBOutletAttr(S.Context, AL));
- }
- static void handleIBOutletCollection(Sema &S, Decl *D, const ParsedAttr &AL) {
- // The iboutletcollection attribute can have zero or one arguments.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
- return;
- }
- if (!checkIBOutletCommon(S, D, AL))
- return;
- ParsedType PT;
- if (AL.hasParsedType())
- PT = AL.getTypeArg();
- else {
- PT = S.getTypeName(S.Context.Idents.get("NSObject"), AL.getLoc(),
- S.getScopeForContext(D->getDeclContext()->getParent()));
- if (!PT) {
- S.Diag(AL.getLoc(), diag::err_iboutletcollection_type) << "NSObject";
- return;
- }
- }
- TypeSourceInfo *QTLoc = nullptr;
- QualType QT = S.GetTypeFromParser(PT, &QTLoc);
- if (!QTLoc)
- QTLoc = S.Context.getTrivialTypeSourceInfo(QT, AL.getLoc());
- // Diagnose use of non-object type in iboutletcollection attribute.
- // FIXME. Gnu attribute extension ignores use of builtin types in
- // attributes. So, __attribute__((iboutletcollection(char))) will be
- // treated as __attribute__((iboutletcollection())).
- if (!QT->isObjCIdType() && !QT->isObjCObjectType()) {
- S.Diag(AL.getLoc(),
- QT->isBuiltinType() ? diag::err_iboutletcollection_builtintype
- : diag::err_iboutletcollection_type) << QT;
- return;
- }
- D->addAttr(::new (S.Context) IBOutletCollectionAttr(S.Context, AL, QTLoc));
- }
- bool Sema::isValidPointerAttrType(QualType T, bool RefOkay) {
- if (RefOkay) {
- if (T->isReferenceType())
- return true;
- } else {
- T = T.getNonReferenceType();
- }
- // The nonnull attribute, and other similar attributes, can be applied to a
- // transparent union that contains a pointer type.
- if (const RecordType *UT = T->getAsUnionType()) {
- if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
- RecordDecl *UD = UT->getDecl();
- for (const auto *I : UD->fields()) {
- QualType QT = I->getType();
- if (QT->isAnyPointerType() || QT->isBlockPointerType())
- return true;
- }
- }
- }
- return T->isAnyPointerType() || T->isBlockPointerType();
- }
- static bool attrNonNullArgCheck(Sema &S, QualType T, const ParsedAttr &AL,
- SourceRange AttrParmRange,
- SourceRange TypeRange,
- bool isReturnValue = false) {
- if (!S.isValidPointerAttrType(T)) {
- if (isReturnValue)
- S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only)
- << AL << AttrParmRange << TypeRange;
- else
- S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only)
- << AL << AttrParmRange << TypeRange << 0;
- return false;
- }
- return true;
- }
- static void handleNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- SmallVector<ParamIdx, 8> NonNullArgs;
- for (unsigned I = 0; I < AL.getNumArgs(); ++I) {
- Expr *Ex = AL.getArgAsExpr(I);
- ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, I + 1, Ex, Idx))
- return;
- // Is the function argument a pointer type?
- if (Idx.getASTIndex() < getFunctionOrMethodNumParams(D) &&
- !attrNonNullArgCheck(
- S, getFunctionOrMethodParamType(D, Idx.getASTIndex()), AL,
- Ex->getSourceRange(),
- getFunctionOrMethodParamRange(D, Idx.getASTIndex())))
- continue;
- NonNullArgs.push_back(Idx);
- }
- // If no arguments were specified to __attribute__((nonnull)) then all pointer
- // arguments have a nonnull attribute; warn if there aren't any. Skip this
- // check if the attribute came from a macro expansion or a template
- // instantiation.
- if (NonNullArgs.empty() && AL.getLoc().isFileID() &&
- !S.inTemplateInstantiation()) {
- bool AnyPointers = isFunctionOrMethodVariadic(D);
- for (unsigned I = 0, E = getFunctionOrMethodNumParams(D);
- I != E && !AnyPointers; ++I) {
- QualType T = getFunctionOrMethodParamType(D, I);
- if (T->isDependentType() || S.isValidPointerAttrType(T))
- AnyPointers = true;
- }
- if (!AnyPointers)
- S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_no_pointers);
- }
- ParamIdx *Start = NonNullArgs.data();
- unsigned Size = NonNullArgs.size();
- llvm::array_pod_sort(Start, Start + Size);
- D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, Start, Size));
- }
- static void handleNonNullAttrParameter(Sema &S, ParmVarDecl *D,
- const ParsedAttr &AL) {
- if (AL.getNumArgs() > 0) {
- if (D->getFunctionType()) {
- handleNonNullAttr(S, D, AL);
- } else {
- S.Diag(AL.getLoc(), diag::warn_attribute_nonnull_parm_no_args)
- << D->getSourceRange();
- }
- return;
- }
- // Is the argument a pointer type?
- if (!attrNonNullArgCheck(S, D->getType(), AL, SourceRange(),
- D->getSourceRange()))
- return;
- D->addAttr(::new (S.Context) NonNullAttr(S.Context, AL, nullptr, 0));
- }
- static void handleReturnsNonNullAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- QualType ResultType = getFunctionOrMethodResultType(D);
- SourceRange SR = getFunctionOrMethodResultSourceRange(D);
- if (!attrNonNullArgCheck(S, ResultType, AL, SourceRange(), SR,
- /* isReturnValue */ true))
- return;
- D->addAttr(::new (S.Context) ReturnsNonNullAttr(S.Context, AL));
- }
- static void handleNoEscapeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (D->isInvalidDecl())
- return;
- // noescape only applies to pointer types.
- QualType T = cast<ParmVarDecl>(D)->getType();
- if (!S.isValidPointerAttrType(T, /* RefOkay */ true)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_pointers_only)
- << AL << AL.getRange() << 0;
- return;
- }
- D->addAttr(::new (S.Context) NoEscapeAttr(S.Context, AL));
- }
- static void handleAssumeAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- Expr *E = AL.getArgAsExpr(0),
- *OE = AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr;
- S.AddAssumeAlignedAttr(D, AL, E, OE);
- }
- static void handleAllocAlignAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.AddAllocAlignAttr(D, AL, AL.getArgAsExpr(0));
- }
- void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
- Expr *OE) {
- QualType ResultType = getFunctionOrMethodResultType(D);
- SourceRange SR = getFunctionOrMethodResultSourceRange(D);
- AssumeAlignedAttr TmpAttr(Context, CI, E, OE);
- SourceLocation AttrLoc = TmpAttr.getLocation();
- if (!isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
- Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
- << &TmpAttr << TmpAttr.getRange() << SR;
- return;
- }
- if (!E->isValueDependent()) {
- llvm::APSInt I(64);
- if (!E->isIntegerConstantExpr(I, Context)) {
- if (OE)
- Diag(AttrLoc, diag::err_attribute_argument_n_type)
- << &TmpAttr << 1 << AANT_ArgumentIntegerConstant
- << E->getSourceRange();
- else
- Diag(AttrLoc, diag::err_attribute_argument_type)
- << &TmpAttr << AANT_ArgumentIntegerConstant
- << E->getSourceRange();
- return;
- }
- if (!I.isPowerOf2()) {
- Diag(AttrLoc, diag::err_alignment_not_power_of_two)
- << E->getSourceRange();
- return;
- }
- }
- if (OE) {
- if (!OE->isValueDependent()) {
- llvm::APSInt I(64);
- if (!OE->isIntegerConstantExpr(I, Context)) {
- Diag(AttrLoc, diag::err_attribute_argument_n_type)
- << &TmpAttr << 2 << AANT_ArgumentIntegerConstant
- << OE->getSourceRange();
- return;
- }
- }
- }
- D->addAttr(::new (Context) AssumeAlignedAttr(Context, CI, E, OE));
- }
- void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI,
- Expr *ParamExpr) {
- QualType ResultType = getFunctionOrMethodResultType(D);
- AllocAlignAttr TmpAttr(Context, CI, ParamIdx());
- SourceLocation AttrLoc = CI.getLoc();
- if (!ResultType->isDependentType() &&
- !isValidPointerAttrType(ResultType, /* RefOkay */ true)) {
- Diag(AttrLoc, diag::warn_attribute_return_pointers_refs_only)
- << &TmpAttr << CI.getRange() << getFunctionOrMethodResultSourceRange(D);
- return;
- }
- ParamIdx Idx;
- const auto *FuncDecl = cast<FunctionDecl>(D);
- if (!checkFunctionOrMethodParameterIndex(*this, FuncDecl, TmpAttr,
- /*AttrArgNum=*/1, ParamExpr, Idx))
- return;
- QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
- if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) {
- Diag(ParamExpr->getBeginLoc(), diag::err_attribute_integers_only)
- << &TmpAttr
- << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange();
- return;
- }
- D->addAttr(::new (Context) AllocAlignAttr(Context, CI, Idx));
- }
- /// Normalize the attribute, __foo__ becomes foo.
- /// Returns true if normalization was applied.
- static bool normalizeName(StringRef &AttrName) {
- if (AttrName.size() > 4 && AttrName.startswith("__") &&
- AttrName.endswith("__")) {
- AttrName = AttrName.drop_front(2).drop_back(2);
- return true;
- }
- return false;
- }
- static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // This attribute must be applied to a function declaration. The first
- // argument to the attribute must be an identifier, the name of the resource,
- // for example: malloc. The following arguments must be argument indexes, the
- // arguments must be of integer type for Returns, otherwise of pointer type.
- // The difference between Holds and Takes is that a pointer may still be used
- // after being held. free() should be __attribute((ownership_takes)), whereas
- // a list append function may well be __attribute((ownership_holds)).
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
- // Figure out our Kind.
- OwnershipAttr::OwnershipKind K =
- OwnershipAttr(S.Context, AL, nullptr, nullptr, 0).getOwnKind();
- // Check arguments.
- switch (K) {
- case OwnershipAttr::Takes:
- case OwnershipAttr::Holds:
- if (AL.getNumArgs() < 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_few_arguments) << AL << 2;
- return;
- }
- break;
- case OwnershipAttr::Returns:
- if (AL.getNumArgs() > 2) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
- return;
- }
- break;
- }
- IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident;
- StringRef ModuleName = Module->getName();
- if (normalizeName(ModuleName)) {
- Module = &S.PP.getIdentifierTable().get(ModuleName);
- }
- SmallVector<ParamIdx, 8> OwnershipArgs;
- for (unsigned i = 1; i < AL.getNumArgs(); ++i) {
- Expr *Ex = AL.getArgAsExpr(i);
- ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, i, Ex, Idx))
- return;
- // Is the function argument a pointer type?
- QualType T = getFunctionOrMethodParamType(D, Idx.getASTIndex());
- int Err = -1; // No error
- switch (K) {
- case OwnershipAttr::Takes:
- case OwnershipAttr::Holds:
- if (!T->isAnyPointerType() && !T->isBlockPointerType())
- Err = 0;
- break;
- case OwnershipAttr::Returns:
- if (!T->isIntegerType())
- Err = 1;
- break;
- }
- if (-1 != Err) {
- S.Diag(AL.getLoc(), diag::err_ownership_type) << AL << Err
- << Ex->getSourceRange();
- return;
- }
- // Check we don't have a conflict with another ownership attribute.
- for (const auto *I : D->specific_attrs<OwnershipAttr>()) {
- // Cannot have two ownership attributes of different kinds for the same
- // index.
- if (I->getOwnKind() != K && I->args_end() !=
- std::find(I->args_begin(), I->args_end(), Idx)) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I;
- return;
- } else if (K == OwnershipAttr::Returns &&
- I->getOwnKind() == OwnershipAttr::Returns) {
- // A returns attribute conflicts with any other returns attribute using
- // a different index.
- if (std::find(I->args_begin(), I->args_end(), Idx) == I->args_end()) {
- S.Diag(I->getLocation(), diag::err_ownership_returns_index_mismatch)
- << I->args_begin()->getSourceIndex();
- if (I->args_size())
- S.Diag(AL.getLoc(), diag::note_ownership_returns_index_mismatch)
- << Idx.getSourceIndex() << Ex->getSourceRange();
- return;
- }
- }
- }
- OwnershipArgs.push_back(Idx);
- }
- ParamIdx *Start = OwnershipArgs.data();
- unsigned Size = OwnershipArgs.size();
- llvm::array_pod_sort(Start, Start + Size);
- D->addAttr(::new (S.Context)
- OwnershipAttr(S.Context, AL, Module, Start, Size));
- }
- static void handleWeakRefAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Check the attribute arguments.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
- return;
- }
- // gcc rejects
- // class c {
- // static int a __attribute__((weakref ("v2")));
- // static int b() __attribute__((weakref ("f3")));
- // };
- // and ignores the attributes of
- // void f(void) {
- // static int a __attribute__((weakref ("v2")));
- // }
- // we reject them
- const DeclContext *Ctx = D->getDeclContext()->getRedeclContext();
- if (!Ctx->isFileContext()) {
- S.Diag(AL.getLoc(), diag::err_attribute_weakref_not_global_context)
- << cast<NamedDecl>(D);
- return;
- }
- // The GCC manual says
- //
- // At present, a declaration to which `weakref' is attached can only
- // be `static'.
- //
- // It also says
- //
- // Without a TARGET,
- // given as an argument to `weakref' or to `alias', `weakref' is
- // equivalent to `weak'.
- //
- // gcc 4.4.1 will accept
- // int a7 __attribute__((weakref));
- // as
- // int a7 __attribute__((weak));
- // This looks like a bug in gcc. We reject that for now. We should revisit
- // it if this behaviour is actually used.
- // GCC rejects
- // static ((alias ("y"), weakref)).
- // Should we? How to check that weakref is before or after alias?
- // FIXME: it would be good for us to keep the WeakRefAttr as-written instead
- // of transforming it into an AliasAttr. The WeakRefAttr never uses the
- // StringRef parameter it was given anyway.
- StringRef Str;
- if (AL.getNumArgs() && S.checkStringLiteralArgumentAttr(AL, 0, Str))
- // GCC will accept anything as the argument of weakref. Should we
- // check for an existing decl?
- D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
- D->addAttr(::new (S.Context) WeakRefAttr(S.Context, AL));
- }
- static void handleIFuncAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Str;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
- return;
- // Aliases should be on declarations, not definitions.
- const auto *FD = cast<FunctionDecl>(D);
- if (FD->isThisDeclarationADefinition()) {
- S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 1;
- return;
- }
- D->addAttr(::new (S.Context) IFuncAttr(S.Context, AL, Str));
- }
- static void handleAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Str;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
- return;
- if (S.Context.getTargetInfo().getTriple().isOSDarwin()) {
- S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_darwin);
- return;
- }
- if (S.Context.getTargetInfo().getTriple().isNVPTX()) {
- S.Diag(AL.getLoc(), diag::err_alias_not_supported_on_nvptx);
- }
- // Aliases should be on declarations, not definitions.
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->isThisDeclarationADefinition()) {
- S.Diag(AL.getLoc(), diag::err_alias_is_definition) << FD << 0;
- return;
- }
- } else {
- const auto *VD = cast<VarDecl>(D);
- if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) {
- S.Diag(AL.getLoc(), diag::err_alias_is_definition) << VD << 0;
- return;
- }
- }
- // Mark target used to prevent unneeded-internal-declaration warnings.
- if (!S.LangOpts.CPlusPlus) {
- // FIXME: demangle Str for C++, as the attribute refers to the mangled
- // linkage name, not the pre-mangled identifier.
- const DeclarationNameInfo target(&S.Context.Idents.get(Str), AL.getLoc());
- LookupResult LR(S, target, Sema::LookupOrdinaryName);
- if (S.LookupQualifiedName(LR, S.getCurLexicalContext()))
- for (NamedDecl *ND : LR)
- ND->markUsed(S.Context);
- }
- D->addAttr(::new (S.Context) AliasAttr(S.Context, AL, Str));
- }
- static void handleTLSModelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Model;
- SourceLocation LiteralLoc;
- // Check that it is a string.
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Model, &LiteralLoc))
- return;
- // Check that the value.
- if (Model != "global-dynamic" && Model != "local-dynamic"
- && Model != "initial-exec" && Model != "local-exec") {
- S.Diag(LiteralLoc, diag::err_attr_tlsmodel_arg);
- return;
- }
- D->addAttr(::new (S.Context) TLSModelAttr(S.Context, AL, Model));
- }
- static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- QualType ResultType = getFunctionOrMethodResultType(D);
- if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) {
- D->addAttr(::new (S.Context) RestrictAttr(S.Context, AL));
- return;
- }
- S.Diag(AL.getLoc(), diag::warn_attribute_return_pointers_only)
- << AL << getFunctionOrMethodResultSourceRange(D);
- }
- static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- FunctionDecl *FD = cast<FunctionDecl>(D);
- if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (MD->getParent()->isLambda()) {
- S.Diag(AL.getLoc(), diag::err_attribute_dll_lambda) << AL;
- return;
- }
- }
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- SmallVector<IdentifierInfo *, 8> CPUs;
- for (unsigned ArgNo = 0; ArgNo < getNumAttributeArgs(AL); ++ArgNo) {
- if (!AL.isArgIdent(ArgNo)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
- IdentifierLoc *CPUArg = AL.getArgAsIdent(ArgNo);
- StringRef CPUName = CPUArg->Ident->getName().trim();
- if (!S.Context.getTargetInfo().validateCPUSpecificCPUDispatch(CPUName)) {
- S.Diag(CPUArg->Loc, diag::err_invalid_cpu_specific_dispatch_value)
- << CPUName << (AL.getKind() == ParsedAttr::AT_CPUDispatch);
- return;
- }
- const TargetInfo &Target = S.Context.getTargetInfo();
- if (llvm::any_of(CPUs, [CPUName, &Target](const IdentifierInfo *Cur) {
- return Target.CPUSpecificManglingCharacter(CPUName) ==
- Target.CPUSpecificManglingCharacter(Cur->getName());
- })) {
- S.Diag(AL.getLoc(), diag::warn_multiversion_duplicate_entries);
- return;
- }
- CPUs.push_back(CPUArg->Ident);
- }
- FD->setIsMultiVersion(true);
- if (AL.getKind() == ParsedAttr::AT_CPUSpecific)
- D->addAttr(::new (S.Context)
- CPUSpecificAttr(S.Context, AL, CPUs.data(), CPUs.size()));
- else
- D->addAttr(::new (S.Context)
- CPUDispatchAttr(S.Context, AL, CPUs.data(), CPUs.size()));
- }
- static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (S.LangOpts.CPlusPlus) {
- S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
- << AL << AttributeLangSupport::Cpp;
- return;
- }
- if (CommonAttr *CA = S.mergeCommonAttr(D, AL))
- D->addAttr(CA);
- }
- static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL))
- return;
- if (AL.isDeclspecAttribute()) {
- const auto &Triple = S.getASTContext().getTargetInfo().getTriple();
- const auto &Arch = Triple.getArch();
- if (Arch != llvm::Triple::x86 &&
- (Arch != llvm::Triple::arm && Arch != llvm::Triple::thumb)) {
- S.Diag(AL.getLoc(), diag::err_attribute_not_supported_on_arch)
- << AL << Triple.getArchName();
- return;
- }
- }
- D->addAttr(::new (S.Context) NakedAttr(S.Context, AL));
- }
- static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
- if (hasDeclarator(D)) return;
- if (!isa<ObjCMethodDecl>(D)) {
- S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type)
- << Attrs << ExpectedFunctionOrMethod;
- return;
- }
- D->addAttr(::new (S.Context) NoReturnAttr(S.Context, Attrs));
- }
- static void handleNoCfCheckAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) {
- if (!S.getLangOpts().CFProtectionBranch)
- S.Diag(Attrs.getLoc(), diag::warn_nocf_check_attribute_ignored);
- else
- handleSimpleAttribute<AnyX86NoCfCheckAttr>(S, D, Attrs);
- }
- bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) {
- if (!checkAttributeNumArgs(*this, Attrs, 0)) {
- Attrs.setInvalid();
- return true;
- }
- return false;
- }
- bool Sema::CheckAttrTarget(const ParsedAttr &AL) {
- // Check whether the attribute is valid on the current target.
- if (!AL.existsInTarget(Context.getTargetInfo())) {
- Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL;
- AL.setInvalid();
- return true;
- }
- return false;
- }
- static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // The checking path for 'noreturn' and 'analyzer_noreturn' are different
- // because 'analyzer_noreturn' does not impact the type.
- if (!isFunctionOrMethodOrBlock(D)) {
- ValueDecl *VD = dyn_cast<ValueDecl>(D);
- if (!VD || (!VD->getType()->isBlockPointerType() &&
- !VD->getType()->isFunctionPointerType())) {
- S.Diag(AL.getLoc(), AL.isCXX11Attribute()
- ? diag::err_attribute_wrong_decl_type
- : diag::warn_attribute_wrong_decl_type)
- << AL << ExpectedFunctionMethodOrBlock;
- return;
- }
- }
- D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(S.Context, AL));
- }
- // PS3 PPU-specific.
- static void handleVecReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- /*
- Returning a Vector Class in Registers
- According to the PPU ABI specifications, a class with a single member of
- vector type is returned in memory when used as the return value of a
- function.
- This results in inefficient code when implementing vector classes. To return
- the value in a single vector register, add the vecreturn attribute to the
- class definition. This attribute is also applicable to struct types.
- Example:
- struct Vector
- {
- __vector float xyzw;
- } __attribute__((vecreturn));
- Vector Add(Vector lhs, Vector rhs)
- {
- Vector result;
- result.xyzw = vec_add(lhs.xyzw, rhs.xyzw);
- return result; // This will be returned in a register
- }
- */
- if (VecReturnAttr *A = D->getAttr<VecReturnAttr>()) {
- S.Diag(AL.getLoc(), diag::err_repeat_attribute) << A;
- return;
- }
- const auto *R = cast<RecordDecl>(D);
- int count = 0;
- if (!isa<CXXRecordDecl>(R)) {
- S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member);
- return;
- }
- if (!cast<CXXRecordDecl>(R)->isPOD()) {
- S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_pod_record);
- return;
- }
- for (const auto *I : R->fields()) {
- if ((count == 1) || !I->getType()->isVectorType()) {
- S.Diag(AL.getLoc(), diag::err_attribute_vecreturn_only_vector_member);
- return;
- }
- count++;
- }
- D->addAttr(::new (S.Context) VecReturnAttr(S.Context, AL));
- }
- static void handleDependencyAttr(Sema &S, Scope *Scope, Decl *D,
- const ParsedAttr &AL) {
- if (isa<ParmVarDecl>(D)) {
- // [[carries_dependency]] can only be applied to a parameter if it is a
- // parameter of a function declaration or lambda.
- if (!(Scope->getFlags() & clang::Scope::FunctionDeclarationScope)) {
- S.Diag(AL.getLoc(),
- diag::err_carries_dependency_param_not_function_decl);
- return;
- }
- }
- D->addAttr(::new (S.Context) CarriesDependencyAttr(S.Context, AL));
- }
- static void handleUnusedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- bool IsCXX17Attr = AL.isCXX11Attribute() && !AL.getScopeName();
- // If this is spelled as the standard C++17 attribute, but not in C++17, warn
- // about using it as an extension.
- if (!S.getLangOpts().CPlusPlus17 && IsCXX17Attr)
- S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
- D->addAttr(::new (S.Context) UnusedAttr(S.Context, AL));
- }
- static void handleConstructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t priority = ConstructorAttr::DefaultPriority;
- if (AL.getNumArgs() &&
- !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
- return;
- D->addAttr(::new (S.Context) ConstructorAttr(S.Context, AL, priority));
- }
- static void handleDestructorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t priority = DestructorAttr::DefaultPriority;
- if (AL.getNumArgs() &&
- !checkUInt32Argument(S, AL, AL.getArgAsExpr(0), priority))
- return;
- D->addAttr(::new (S.Context) DestructorAttr(S.Context, AL, priority));
- }
- template <typename AttrTy>
- static void handleAttrWithMessage(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Handle the case where the attribute has a text message.
- StringRef Str;
- if (AL.getNumArgs() == 1 && !S.checkStringLiteralArgumentAttr(AL, 0, Str))
- return;
- D->addAttr(::new (S.Context) AttrTy(S.Context, AL, Str));
- }
- static void handleObjCSuppresProtocolAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!cast<ObjCProtocolDecl>(D)->isThisDeclarationADefinition()) {
- S.Diag(AL.getLoc(), diag::err_objc_attr_protocol_requires_definition)
- << AL << AL.getRange();
- return;
- }
- D->addAttr(::new (S.Context) ObjCExplicitProtocolImplAttr(S.Context, AL));
- }
- static bool checkAvailabilityAttr(Sema &S, SourceRange Range,
- IdentifierInfo *Platform,
- VersionTuple Introduced,
- VersionTuple Deprecated,
- VersionTuple Obsoleted) {
- StringRef PlatformName
- = AvailabilityAttr::getPrettyPlatformName(Platform->getName());
- if (PlatformName.empty())
- PlatformName = Platform->getName();
- // Ensure that Introduced <= Deprecated <= Obsoleted (although not all
- // of these steps are needed).
- if (!Introduced.empty() && !Deprecated.empty() &&
- !(Introduced <= Deprecated)) {
- S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
- << 1 << PlatformName << Deprecated.getAsString()
- << 0 << Introduced.getAsString();
- return true;
- }
- if (!Introduced.empty() && !Obsoleted.empty() &&
- !(Introduced <= Obsoleted)) {
- S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
- << 2 << PlatformName << Obsoleted.getAsString()
- << 0 << Introduced.getAsString();
- return true;
- }
- if (!Deprecated.empty() && !Obsoleted.empty() &&
- !(Deprecated <= Obsoleted)) {
- S.Diag(Range.getBegin(), diag::warn_availability_version_ordering)
- << 2 << PlatformName << Obsoleted.getAsString()
- << 1 << Deprecated.getAsString();
- return true;
- }
- return false;
- }
- /// Check whether the two versions match.
- ///
- /// If either version tuple is empty, then they are assumed to match. If
- /// \p BeforeIsOkay is true, then \p X can be less than or equal to \p Y.
- static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
- bool BeforeIsOkay) {
- if (X.empty() || Y.empty())
- return true;
- if (X == Y)
- return true;
- if (BeforeIsOkay && X < Y)
- return true;
- return false;
- }
- AvailabilityAttr *Sema::mergeAvailabilityAttr(
- NamedDecl *D, const AttributeCommonInfo &CI, IdentifierInfo *Platform,
- bool Implicit, VersionTuple Introduced, VersionTuple Deprecated,
- VersionTuple Obsoleted, bool IsUnavailable, StringRef Message,
- bool IsStrict, StringRef Replacement, AvailabilityMergeKind AMK,
- int Priority) {
- VersionTuple MergedIntroduced = Introduced;
- VersionTuple MergedDeprecated = Deprecated;
- VersionTuple MergedObsoleted = Obsoleted;
- bool FoundAny = false;
- bool OverrideOrImpl = false;
- switch (AMK) {
- case AMK_None:
- case AMK_Redeclaration:
- OverrideOrImpl = false;
- break;
- case AMK_Override:
- case AMK_ProtocolImplementation:
- OverrideOrImpl = true;
- break;
- }
- if (D->hasAttrs()) {
- AttrVec &Attrs = D->getAttrs();
- for (unsigned i = 0, e = Attrs.size(); i != e;) {
- const auto *OldAA = dyn_cast<AvailabilityAttr>(Attrs[i]);
- if (!OldAA) {
- ++i;
- continue;
- }
- IdentifierInfo *OldPlatform = OldAA->getPlatform();
- if (OldPlatform != Platform) {
- ++i;
- continue;
- }
- // If there is an existing availability attribute for this platform that
- // has a lower priority use the existing one and discard the new
- // attribute.
- if (OldAA->getPriority() < Priority)
- return nullptr;
- // If there is an existing attribute for this platform that has a higher
- // priority than the new attribute then erase the old one and continue
- // processing the attributes.
- if (OldAA->getPriority() > Priority) {
- Attrs.erase(Attrs.begin() + i);
- --e;
- continue;
- }
- FoundAny = true;
- VersionTuple OldIntroduced = OldAA->getIntroduced();
- VersionTuple OldDeprecated = OldAA->getDeprecated();
- VersionTuple OldObsoleted = OldAA->getObsoleted();
- bool OldIsUnavailable = OldAA->getUnavailable();
- if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl) ||
- !versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl) ||
- !versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl) ||
- !(OldIsUnavailable == IsUnavailable ||
- (OverrideOrImpl && !OldIsUnavailable && IsUnavailable))) {
- if (OverrideOrImpl) {
- int Which = -1;
- VersionTuple FirstVersion;
- VersionTuple SecondVersion;
- if (!versionsMatch(OldIntroduced, Introduced, OverrideOrImpl)) {
- Which = 0;
- FirstVersion = OldIntroduced;
- SecondVersion = Introduced;
- } else if (!versionsMatch(Deprecated, OldDeprecated, OverrideOrImpl)) {
- Which = 1;
- FirstVersion = Deprecated;
- SecondVersion = OldDeprecated;
- } else if (!versionsMatch(Obsoleted, OldObsoleted, OverrideOrImpl)) {
- Which = 2;
- FirstVersion = Obsoleted;
- SecondVersion = OldObsoleted;
- }
- if (Which == -1) {
- Diag(OldAA->getLocation(),
- diag::warn_mismatched_availability_override_unavail)
- << AvailabilityAttr::getPrettyPlatformName(Platform->getName())
- << (AMK == AMK_Override);
- } else {
- Diag(OldAA->getLocation(),
- diag::warn_mismatched_availability_override)
- << Which
- << AvailabilityAttr::getPrettyPlatformName(Platform->getName())
- << FirstVersion.getAsString() << SecondVersion.getAsString()
- << (AMK == AMK_Override);
- }
- if (AMK == AMK_Override)
- Diag(CI.getLoc(), diag::note_overridden_method);
- else
- Diag(CI.getLoc(), diag::note_protocol_method);
- } else {
- Diag(OldAA->getLocation(), diag::warn_mismatched_availability);
- Diag(CI.getLoc(), diag::note_previous_attribute);
- }
- Attrs.erase(Attrs.begin() + i);
- --e;
- continue;
- }
- VersionTuple MergedIntroduced2 = MergedIntroduced;
- VersionTuple MergedDeprecated2 = MergedDeprecated;
- VersionTuple MergedObsoleted2 = MergedObsoleted;
- if (MergedIntroduced2.empty())
- MergedIntroduced2 = OldIntroduced;
- if (MergedDeprecated2.empty())
- MergedDeprecated2 = OldDeprecated;
- if (MergedObsoleted2.empty())
- MergedObsoleted2 = OldObsoleted;
- if (checkAvailabilityAttr(*this, OldAA->getRange(), Platform,
- MergedIntroduced2, MergedDeprecated2,
- MergedObsoleted2)) {
- Attrs.erase(Attrs.begin() + i);
- --e;
- continue;
- }
- MergedIntroduced = MergedIntroduced2;
- MergedDeprecated = MergedDeprecated2;
- MergedObsoleted = MergedObsoleted2;
- ++i;
- }
- }
- if (FoundAny &&
- MergedIntroduced == Introduced &&
- MergedDeprecated == Deprecated &&
- MergedObsoleted == Obsoleted)
- return nullptr;
- // Only create a new attribute if !OverrideOrImpl, but we want to do
- // the checking.
- if (!checkAvailabilityAttr(*this, CI.getRange(), Platform, MergedIntroduced,
- MergedDeprecated, MergedObsoleted) &&
- !OverrideOrImpl) {
- auto *Avail = ::new (Context) AvailabilityAttr(
- Context, CI, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable,
- Message, IsStrict, Replacement, Priority);
- Avail->setImplicit(Implicit);
- return Avail;
- }
- return nullptr;
- }
- static void handleAvailabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeNumArgs(S, AL, 1))
- return;
- IdentifierLoc *Platform = AL.getArgAsIdent(0);
- IdentifierInfo *II = Platform->Ident;
- if (AvailabilityAttr::getPrettyPlatformName(II->getName()).empty())
- S.Diag(Platform->Loc, diag::warn_availability_unknown_platform)
- << Platform->Ident;
- auto *ND = dyn_cast<NamedDecl>(D);
- if (!ND) // We warned about this already, so just return.
- return;
- AvailabilityChange Introduced = AL.getAvailabilityIntroduced();
- AvailabilityChange Deprecated = AL.getAvailabilityDeprecated();
- AvailabilityChange Obsoleted = AL.getAvailabilityObsoleted();
- bool IsUnavailable = AL.getUnavailableLoc().isValid();
- bool IsStrict = AL.getStrictLoc().isValid();
- StringRef Str;
- if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getMessageExpr()))
- Str = SE->getString();
- StringRef Replacement;
- if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getReplacementExpr()))
- Replacement = SE->getString();
- if (II->isStr("swift")) {
- if (Introduced.isValid() || Obsoleted.isValid() ||
- (!IsUnavailable && !Deprecated.isValid())) {
- S.Diag(AL.getLoc(),
- diag::warn_availability_swift_unavailable_deprecated_only);
- return;
- }
- }
- int PriorityModifier = AL.isPragmaClangAttribute()
- ? Sema::AP_PragmaClangAttribute
- : Sema::AP_Explicit;
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL, II, false /*Implicit*/, Introduced.Version, Deprecated.Version,
- Obsoleted.Version, IsUnavailable, Str, IsStrict, Replacement,
- Sema::AMK_None, PriorityModifier);
- if (NewAttr)
- D->addAttr(NewAttr);
- // Transcribe "ios" to "watchos" (and add a new attribute) if the versioning
- // matches before the start of the watchOS platform.
- if (S.Context.getTargetInfo().getTriple().isWatchOS()) {
- IdentifierInfo *NewII = nullptr;
- if (II->getName() == "ios")
- NewII = &S.Context.Idents.get("watchos");
- else if (II->getName() == "ios_app_extension")
- NewII = &S.Context.Idents.get("watchos_app_extension");
- if (NewII) {
- auto adjustWatchOSVersion = [](VersionTuple Version) -> VersionTuple {
- if (Version.empty())
- return Version;
- auto Major = Version.getMajor();
- auto NewMajor = Major >= 9 ? Major - 7 : 0;
- if (NewMajor >= 2) {
- if (Version.getMinor().hasValue()) {
- if (Version.getSubminor().hasValue())
- return VersionTuple(NewMajor, Version.getMinor().getValue(),
- Version.getSubminor().getValue());
- else
- return VersionTuple(NewMajor, Version.getMinor().getValue());
- }
- return VersionTuple(NewMajor);
- }
- return VersionTuple(2, 0);
- };
- auto NewIntroduced = adjustWatchOSVersion(Introduced.Version);
- auto NewDeprecated = adjustWatchOSVersion(Deprecated.Version);
- auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL, NewII, true /*Implicit*/, NewIntroduced, NewDeprecated,
- NewObsoleted, IsUnavailable, Str, IsStrict, Replacement,
- Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform);
- if (NewAttr)
- D->addAttr(NewAttr);
- }
- } else if (S.Context.getTargetInfo().getTriple().isTvOS()) {
- // Transcribe "ios" to "tvos" (and add a new attribute) if the versioning
- // matches before the start of the tvOS platform.
- IdentifierInfo *NewII = nullptr;
- if (II->getName() == "ios")
- NewII = &S.Context.Idents.get("tvos");
- else if (II->getName() == "ios_app_extension")
- NewII = &S.Context.Idents.get("tvos_app_extension");
- if (NewII) {
- AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(
- ND, AL, NewII, true /*Implicit*/, Introduced.Version,
- Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, IsStrict,
- Replacement, Sema::AMK_None,
- PriorityModifier + Sema::AP_InferredFromOtherPlatform);
- if (NewAttr)
- D->addAttr(NewAttr);
- }
- }
- }
- static void handleExternalSourceSymbolAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- assert(checkAttributeAtMostNumArgs(S, AL, 3) &&
- "Invalid number of arguments in an external_source_symbol attribute");
- StringRef Language;
- if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(0)))
- Language = SE->getString();
- StringRef DefinedIn;
- if (const auto *SE = dyn_cast_or_null<StringLiteral>(AL.getArgAsExpr(1)))
- DefinedIn = SE->getString();
- bool IsGeneratedDeclaration = AL.getArgAsIdent(2) != nullptr;
- D->addAttr(::new (S.Context) ExternalSourceSymbolAttr(
- S.Context, AL, Language, DefinedIn, IsGeneratedDeclaration));
- }
- template <class T>
- static T *mergeVisibilityAttr(Sema &S, Decl *D, const AttributeCommonInfo &CI,
- typename T::VisibilityType value) {
- T *existingAttr = D->getAttr<T>();
- if (existingAttr) {
- typename T::VisibilityType existingValue = existingAttr->getVisibility();
- if (existingValue == value)
- return nullptr;
- S.Diag(existingAttr->getLocation(), diag::err_mismatched_visibility);
- S.Diag(CI.getLoc(), diag::note_previous_attribute);
- D->dropAttr<T>();
- }
- return ::new (S.Context) T(S.Context, CI, value);
- }
- VisibilityAttr *Sema::mergeVisibilityAttr(Decl *D,
- const AttributeCommonInfo &CI,
- VisibilityAttr::VisibilityType Vis) {
- return ::mergeVisibilityAttr<VisibilityAttr>(*this, D, CI, Vis);
- }
- TypeVisibilityAttr *
- Sema::mergeTypeVisibilityAttr(Decl *D, const AttributeCommonInfo &CI,
- TypeVisibilityAttr::VisibilityType Vis) {
- return ::mergeVisibilityAttr<TypeVisibilityAttr>(*this, D, CI, Vis);
- }
- static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL,
- bool isTypeVisibility) {
- // Visibility attributes don't mean anything on a typedef.
- if (isa<TypedefNameDecl>(D)) {
- S.Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL;
- return;
- }
- // 'type_visibility' can only go on a type or namespace.
- if (isTypeVisibility &&
- !(isa<TagDecl>(D) ||
- isa<ObjCInterfaceDecl>(D) ||
- isa<NamespaceDecl>(D))) {
- S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type)
- << AL << ExpectedTypeOrNamespace;
- return;
- }
- // Check that the argument is a string literal.
- StringRef TypeStr;
- SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, TypeStr, &LiteralLoc))
- return;
- VisibilityAttr::VisibilityType type;
- if (!VisibilityAttr::ConvertStrToVisibilityType(TypeStr, type)) {
- S.Diag(LiteralLoc, diag::warn_attribute_type_not_supported) << AL
- << TypeStr;
- return;
- }
- // Complain about attempts to use protected visibility on targets
- // (like Darwin) that don't support it.
- if (type == VisibilityAttr::Protected &&
- !S.Context.getTargetInfo().hasProtectedVisibility()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_protected_visibility);
- type = VisibilityAttr::Default;
- }
- Attr *newAttr;
- if (isTypeVisibility) {
- newAttr = S.mergeTypeVisibilityAttr(
- D, AL, (TypeVisibilityAttr::VisibilityType)type);
- } else {
- newAttr = S.mergeVisibilityAttr(D, AL, type);
- }
- if (newAttr)
- D->addAttr(newAttr);
- }
- static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- const auto *M = cast<ObjCMethodDecl>(D);
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
- IdentifierLoc *IL = AL.getArgAsIdent(0);
- ObjCMethodFamilyAttr::FamilyKind F;
- if (!ObjCMethodFamilyAttr::ConvertStrToFamilyKind(IL->Ident->getName(), F)) {
- S.Diag(IL->Loc, diag::warn_attribute_type_not_supported) << AL << IL->Ident;
- return;
- }
- if (F == ObjCMethodFamilyAttr::OMF_init &&
- !M->getReturnType()->isObjCObjectPointerType()) {
- S.Diag(M->getLocation(), diag::err_init_method_bad_return_type)
- << M->getReturnType();
- // Ignore the attribute.
- return;
- }
- D->addAttr(new (S.Context) ObjCMethodFamilyAttr(S.Context, AL, F));
- }
- static void handleObjCNSObject(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- QualType T = TD->getUnderlyingType();
- if (!T->isCARCBridgableType()) {
- S.Diag(TD->getLocation(), diag::err_nsobject_attribute);
- return;
- }
- }
- else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
- QualType T = PD->getType();
- if (!T->isCARCBridgableType()) {
- S.Diag(PD->getLocation(), diag::err_nsobject_attribute);
- return;
- }
- }
- else {
- // It is okay to include this attribute on properties, e.g.:
- //
- // @property (retain, nonatomic) struct Bork *Q __attribute__((NSObject));
- //
- // In this case it follows tradition and suppresses an error in the above
- // case.
- S.Diag(D->getLocation(), diag::warn_nsobject_attribute);
- }
- D->addAttr(::new (S.Context) ObjCNSObjectAttr(S.Context, AL));
- }
- static void handleObjCIndependentClass(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- QualType T = TD->getUnderlyingType();
- if (!T->isObjCObjectPointerType()) {
- S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute);
- return;
- }
- } else {
- S.Diag(D->getLocation(), diag::warn_independentclass_attribute);
- return;
- }
- D->addAttr(::new (S.Context) ObjCIndependentClassAttr(S.Context, AL));
- }
- static void handleBlocksAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
- IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
- BlocksAttr::BlockType type;
- if (!BlocksAttr::ConvertStrToBlockType(II->getName(), type)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
- return;
- }
- D->addAttr(::new (S.Context) BlocksAttr(S.Context, AL, type));
- }
- static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- unsigned sentinel = (unsigned)SentinelAttr::DefaultSentinel;
- if (AL.getNumArgs() > 0) {
- Expr *E = AL.getArgAsExpr(0);
- llvm::APSInt Idx(32);
- if (E->isTypeDependent() || E->isValueDependent() ||
- !E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIntegerConstant << E->getSourceRange();
- return;
- }
- if (Idx.isSigned() && Idx.isNegative()) {
- S.Diag(AL.getLoc(), diag::err_attribute_sentinel_less_than_zero)
- << E->getSourceRange();
- return;
- }
- sentinel = Idx.getZExtValue();
- }
- unsigned nullPos = (unsigned)SentinelAttr::DefaultNullPos;
- if (AL.getNumArgs() > 1) {
- Expr *E = AL.getArgAsExpr(1);
- llvm::APSInt Idx(32);
- if (E->isTypeDependent() || E->isValueDependent() ||
- !E->isIntegerConstantExpr(Idx, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 2 << AANT_ArgumentIntegerConstant << E->getSourceRange();
- return;
- }
- nullPos = Idx.getZExtValue();
- if ((Idx.isSigned() && Idx.isNegative()) || nullPos > 1) {
- // FIXME: This error message could be improved, it would be nice
- // to say what the bounds actually are.
- S.Diag(AL.getLoc(), diag::err_attribute_sentinel_not_zero_or_one)
- << E->getSourceRange();
- return;
- }
- }
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- const FunctionType *FT = FD->getType()->castAs<FunctionType>();
- if (isa<FunctionNoProtoType>(FT)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_named_arguments);
- return;
- }
- if (!cast<FunctionProtoType>(FT)->isVariadic()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
- return;
- }
- } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (!MD->isVariadic()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 0;
- return;
- }
- } else if (const auto *BD = dyn_cast<BlockDecl>(D)) {
- if (!BD->isVariadic()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << 1;
- return;
- }
- } else if (const auto *V = dyn_cast<VarDecl>(D)) {
- QualType Ty = V->getType();
- if (Ty->isBlockPointerType() || Ty->isFunctionPointerType()) {
- const FunctionType *FT = Ty->isFunctionPointerType()
- ? D->getFunctionType()
- : Ty->castAs<BlockPointerType>()->getPointeeType()->getAs<FunctionType>();
- if (!cast<FunctionProtoType>(FT)->isVariadic()) {
- int m = Ty->isFunctionPointerType() ? 0 : 1;
- S.Diag(AL.getLoc(), diag::warn_attribute_sentinel_not_variadic) << m;
- return;
- }
- } else {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << ExpectedFunctionMethodOrBlock;
- return;
- }
- } else {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << ExpectedFunctionMethodOrBlock;
- return;
- }
- D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos));
- }
- static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (D->getFunctionType() &&
- D->getFunctionType()->getReturnType()->isVoidType() &&
- !isa<CXXConstructorDecl>(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 0;
- return;
- }
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D))
- if (MD->getReturnType()->isVoidType()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_void_function_method) << AL << 1;
- return;
- }
- StringRef Str;
- if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) {
- // If this is spelled as the standard C++17 attribute, but not in C++17,
- // warn about using it as an extension. If there are attribute arguments,
- // then claim it's a C++2a extension instead.
- // FIXME: If WG14 does not seem likely to adopt the same feature, add an
- // extension warning for C2x mode.
- const LangOptions &LO = S.getLangOpts();
- if (AL.getNumArgs() == 1) {
- if (LO.CPlusPlus && !LO.CPlusPlus2a)
- S.Diag(AL.getLoc(), diag::ext_cxx2a_attr) << AL;
- // Since this this is spelled [[nodiscard]], get the optional string
- // literal. If in C++ mode, but not in C++2a mode, diagnose as an
- // extension.
- // FIXME: C2x should support this feature as well, even as an extension.
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, nullptr))
- return;
- } else if (LO.CPlusPlus && !LO.CPlusPlus17)
- S.Diag(AL.getLoc(), diag::ext_cxx17_attr) << AL;
- }
- D->addAttr(::new (S.Context) WarnUnusedResultAttr(S.Context, AL, Str));
- }
- static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // weak_import only applies to variable & function declarations.
- bool isDef = false;
- if (!D->canBeWeakImported(isDef)) {
- if (isDef)
- S.Diag(AL.getLoc(), diag::warn_attribute_invalid_on_definition)
- << "weak_import";
- else if (isa<ObjCPropertyDecl>(D) || isa<ObjCMethodDecl>(D) ||
- (S.Context.getTargetInfo().getTriple().isOSDarwin() &&
- (isa<ObjCInterfaceDecl>(D) || isa<EnumDecl>(D)))) {
- // Nothing to warn about here.
- } else
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << ExpectedVariableOrFunction;
- return;
- }
- D->addAttr(::new (S.Context) WeakImportAttr(S.Context, AL));
- }
- // Handles reqd_work_group_size and work_group_size_hint.
- template <typename WorkGroupAttr>
- static void handleWorkGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t WGSize[3];
- for (unsigned i = 0; i < 3; ++i) {
- const Expr *E = AL.getArgAsExpr(i);
- if (!checkUInt32Argument(S, AL, E, WGSize[i], i,
- /*StrictlyUnsigned=*/true))
- return;
- if (WGSize[i] == 0) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
- << AL << E->getSourceRange();
- return;
- }
- }
- WorkGroupAttr *Existing = D->getAttr<WorkGroupAttr>();
- if (Existing && !(Existing->getXDim() == WGSize[0] &&
- Existing->getYDim() == WGSize[1] &&
- Existing->getZDim() == WGSize[2]))
- S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- D->addAttr(::new (S.Context)
- WorkGroupAttr(S.Context, AL, WGSize[0], WGSize[1], WGSize[2]));
- }
- // Handles intel_reqd_sub_group_size.
- static void handleSubGroupSize(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t SGSize;
- const Expr *E = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, E, SGSize))
- return;
- if (SGSize == 0) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_is_zero)
- << AL << E->getSourceRange();
- return;
- }
- OpenCLIntelReqdSubGroupSizeAttr *Existing =
- D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>();
- if (Existing && Existing->getSubGroupSize() != SGSize)
- S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- D->addAttr(::new (S.Context)
- OpenCLIntelReqdSubGroupSizeAttr(S.Context, AL, SGSize));
- }
- static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.hasParsedType()) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
- return;
- }
- TypeSourceInfo *ParmTSI = nullptr;
- QualType ParmType = S.GetTypeFromParser(AL.getTypeArg(), &ParmTSI);
- assert(ParmTSI && "no type source info for attribute argument");
- if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() &&
- (ParmType->isBooleanType() ||
- !ParmType->isIntegralType(S.getASTContext()))) {
- S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL;
- return;
- }
- if (VecTypeHintAttr *A = D->getAttr<VecTypeHintAttr>()) {
- if (!S.Context.hasSameType(A->getTypeHint(), ParmType)) {
- S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- return;
- }
- }
- D->addAttr(::new (S.Context) VecTypeHintAttr(S.Context, AL, ParmTSI));
- }
- SectionAttr *Sema::mergeSectionAttr(Decl *D, const AttributeCommonInfo &CI,
- StringRef Name) {
- // Explicit or partial specializations do not inherit
- // the section attribute from the primary template.
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (CI.getAttributeSpellingListIndex() == SectionAttr::Declspec_allocate &&
- FD->isFunctionTemplateSpecialization())
- return nullptr;
- }
- if (SectionAttr *ExistingAttr = D->getAttr<SectionAttr>()) {
- if (ExistingAttr->getName() == Name)
- return nullptr;
- Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
- << 1 /*section*/;
- Diag(CI.getLoc(), diag::note_previous_attribute);
- return nullptr;
- }
- return ::new (Context) SectionAttr(Context, CI, Name);
- }
- bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) {
- std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName);
- if (!Error.empty()) {
- Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error
- << 1 /*'section'*/;
- return false;
- }
- return true;
- }
- static void handleSectionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Make sure that there is a string literal as the sections's single
- // argument.
- StringRef Str;
- SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
- return;
- if (!S.checkSectionName(LiteralLoc, Str))
- return;
- // If the target wants to validate the section specifier, make it happen.
- std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str);
- if (!Error.empty()) {
- S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
- << Error;
- return;
- }
- SectionAttr *NewAttr = S.mergeSectionAttr(D, AL, Str);
- if (NewAttr)
- D->addAttr(NewAttr);
- }
- // This is used for `__declspec(code_seg("segname"))` on a decl.
- // `#pragma code_seg("segname")` uses checkSectionName() instead.
- static bool checkCodeSegName(Sema &S, SourceLocation LiteralLoc,
- StringRef CodeSegName) {
- std::string Error =
- S.Context.getTargetInfo().isValidSectionSpecifier(CodeSegName);
- if (!Error.empty()) {
- S.Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target)
- << Error << 0 /*'code-seg'*/;
- return false;
- }
- return true;
- }
- CodeSegAttr *Sema::mergeCodeSegAttr(Decl *D, const AttributeCommonInfo &CI,
- StringRef Name) {
- // Explicit or partial specializations do not inherit
- // the code_seg attribute from the primary template.
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->isFunctionTemplateSpecialization())
- return nullptr;
- }
- if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
- if (ExistingAttr->getName() == Name)
- return nullptr;
- Diag(ExistingAttr->getLocation(), diag::warn_mismatched_section)
- << 0 /*codeseg*/;
- Diag(CI.getLoc(), diag::note_previous_attribute);
- return nullptr;
- }
- return ::new (Context) CodeSegAttr(Context, CI, Name);
- }
- static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Str;
- SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc))
- return;
- if (!checkCodeSegName(S, LiteralLoc, Str))
- return;
- if (const auto *ExistingAttr = D->getAttr<CodeSegAttr>()) {
- if (!ExistingAttr->isImplicit()) {
- S.Diag(AL.getLoc(),
- ExistingAttr->getName() == Str
- ? diag::warn_duplicate_codeseg_attribute
- : diag::err_conflicting_codeseg_attribute);
- return;
- }
- D->dropAttr<CodeSegAttr>();
- }
- if (CodeSegAttr *CSA = S.mergeCodeSegAttr(D, AL, Str))
- D->addAttr(CSA);
- }
- // Check for things we'd like to warn about. Multiversioning issues are
- // handled later in the process, once we know how many exist.
- bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
- enum FirstParam { Unsupported, Duplicate };
- enum SecondParam { None, Architecture };
- for (auto Str : {"tune=", "fpmath="})
- if (AttrStr.find(Str) != StringRef::npos)
- return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Unsupported << None << Str;
- TargetAttr::ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
- if (!ParsedAttrs.Architecture.empty() &&
- !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
- return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Unsupported << Architecture << ParsedAttrs.Architecture;
- if (ParsedAttrs.DuplicateArchitecture)
- return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Duplicate << None << "arch=";
- for (const auto &Feature : ParsedAttrs.Features) {
- auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
- if (!Context.getTargetInfo().isValidFeatureName(CurFeature))
- return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
- << Unsupported << None << CurFeature;
- }
- return false;
- }
- static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef Str;
- SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
- S.checkTargetAttr(LiteralLoc, Str))
- return;
- TargetAttr *NewAttr = ::new (S.Context) TargetAttr(S.Context, AL, Str);
- D->addAttr(NewAttr);
- }
- static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- Expr *E = AL.getArgAsExpr(0);
- uint32_t VecWidth;
- if (!checkUInt32Argument(S, AL, E, VecWidth)) {
- AL.setInvalid();
- return;
- }
- MinVectorWidthAttr *Existing = D->getAttr<MinVectorWidthAttr>();
- if (Existing && Existing->getVectorWidth() != VecWidth) {
- S.Diag(AL.getLoc(), diag::warn_duplicate_attribute) << AL;
- return;
- }
- D->addAttr(::new (S.Context) MinVectorWidthAttr(S.Context, AL, VecWidth));
- }
- static void handleCleanupAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- Expr *E = AL.getArgAsExpr(0);
- SourceLocation Loc = E->getExprLoc();
- FunctionDecl *FD = nullptr;
- DeclarationNameInfo NI;
- // gcc only allows for simple identifiers. Since we support more than gcc, we
- // will warn the user.
- if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
- if (DRE->hasQualifier())
- S.Diag(Loc, diag::warn_cleanup_ext);
- FD = dyn_cast<FunctionDecl>(DRE->getDecl());
- NI = DRE->getNameInfo();
- if (!FD) {
- S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 1
- << NI.getName();
- return;
- }
- } else if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(E)) {
- if (ULE->hasExplicitTemplateArgs())
- S.Diag(Loc, diag::warn_cleanup_ext);
- FD = S.ResolveSingleFunctionTemplateSpecialization(ULE, true);
- NI = ULE->getNameInfo();
- if (!FD) {
- S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 2
- << NI.getName();
- if (ULE->getType() == S.Context.OverloadTy)
- S.NoteAllOverloadCandidates(ULE);
- return;
- }
- } else {
- S.Diag(Loc, diag::err_attribute_cleanup_arg_not_function) << 0;
- return;
- }
- if (FD->getNumParams() != 1) {
- S.Diag(Loc, diag::err_attribute_cleanup_func_must_take_one_arg)
- << NI.getName();
- return;
- }
- // We're currently more strict than GCC about what function types we accept.
- // If this ever proves to be a problem it should be easy to fix.
- QualType Ty = S.Context.getPointerType(cast<VarDecl>(D)->getType());
- QualType ParamTy = FD->getParamDecl(0)->getType();
- if (S.CheckAssignmentConstraints(FD->getParamDecl(0)->getLocation(),
- ParamTy, Ty) != Sema::Compatible) {
- S.Diag(Loc, diag::err_attribute_cleanup_func_arg_incompatible_type)
- << NI.getName() << ParamTy << Ty;
- return;
- }
- D->addAttr(::new (S.Context) CleanupAttr(S.Context, AL, FD));
- }
- static void handleEnumExtensibilityAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 0 << AANT_ArgumentIdentifier;
- return;
- }
- EnumExtensibilityAttr::Kind ExtensibilityKind;
- IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
- if (!EnumExtensibilityAttr::ConvertStrToKind(II->getName(),
- ExtensibilityKind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II;
- return;
- }
- D->addAttr(::new (S.Context)
- EnumExtensibilityAttr(S.Context, AL, ExtensibilityKind));
- }
- /// Handle __attribute__((format_arg((idx)))) attribute based on
- /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
- static void handleFormatArgAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- Expr *IdxExpr = AL.getArgAsExpr(0);
- ParamIdx Idx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, IdxExpr, Idx))
- return;
- // Make sure the format string is really a string.
- QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex());
- bool NotNSStringTy = !isNSStringType(Ty, S.Context);
- if (NotNSStringTy &&
- !isCFStringType(Ty, S.Context) &&
- (!Ty->isPointerType() ||
- !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
- S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "a string type" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, 0);
- return;
- }
- Ty = getFunctionOrMethodResultType(D);
- if (!isNSStringType(Ty, S.Context) &&
- !isCFStringType(Ty, S.Context) &&
- (!Ty->isPointerType() ||
- !Ty->castAs<PointerType>()->getPointeeType()->isCharType())) {
- S.Diag(AL.getLoc(), diag::err_format_attribute_result_not)
- << (NotNSStringTy ? "string type" : "NSString")
- << IdxExpr->getSourceRange() << getFunctionOrMethodParamRange(D, 0);
- return;
- }
- D->addAttr(::new (S.Context) FormatArgAttr(S.Context, AL, Idx));
- }
- enum FormatAttrKind {
- CFStringFormat,
- NSStringFormat,
- StrftimeFormat,
- SupportedFormat,
- IgnoredFormat,
- InvalidFormat
- };
- /// getFormatAttrKind - Map from format attribute names to supported format
- /// types.
- static FormatAttrKind getFormatAttrKind(StringRef Format) {
- return llvm::StringSwitch<FormatAttrKind>(Format)
- // Check for formats that get handled specially.
- .Case("NSString", NSStringFormat)
- .Case("CFString", CFStringFormat)
- .Case("strftime", StrftimeFormat)
- // Otherwise, check for supported formats.
- .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat)
- .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat)
- .Case("kprintf", SupportedFormat) // OpenBSD.
- .Case("freebsd_kprintf", SupportedFormat) // FreeBSD.
- .Case("os_trace", SupportedFormat)
- .Case("os_log", SupportedFormat)
- .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat)
- .Default(InvalidFormat);
- }
- /// Handle __attribute__((init_priority(priority))) attributes based on
- /// http://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html
- static void handleInitPriorityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!S.getLangOpts().CPlusPlus) {
- S.Diag(AL.getLoc(), diag::warn_attribute_ignored) << AL;
- return;
- }
- if (S.getCurFunctionOrMethodDecl()) {
- S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
- AL.setInvalid();
- return;
- }
- QualType T = cast<VarDecl>(D)->getType();
- if (S.Context.getAsArrayType(T))
- T = S.Context.getBaseElementType(T);
- if (!T->getAs<RecordType>()) {
- S.Diag(AL.getLoc(), diag::err_init_priority_object_attr);
- AL.setInvalid();
- return;
- }
- Expr *E = AL.getArgAsExpr(0);
- uint32_t prioritynum;
- if (!checkUInt32Argument(S, AL, E, prioritynum)) {
- AL.setInvalid();
- return;
- }
- if (prioritynum < 101 || prioritynum > 65535) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_range)
- << E->getSourceRange() << AL << 101 << 65535;
- AL.setInvalid();
- return;
- }
- D->addAttr(::new (S.Context) InitPriorityAttr(S.Context, AL, prioritynum));
- }
- FormatAttr *Sema::mergeFormatAttr(Decl *D, const AttributeCommonInfo &CI,
- IdentifierInfo *Format, int FormatIdx,
- int FirstArg) {
- // Check whether we already have an equivalent format attribute.
- for (auto *F : D->specific_attrs<FormatAttr>()) {
- if (F->getType() == Format &&
- F->getFormatIdx() == FormatIdx &&
- F->getFirstArg() == FirstArg) {
- // If we don't have a valid location for this attribute, adopt the
- // location.
- if (F->getLocation().isInvalid())
- F->setRange(CI.getRange());
- return nullptr;
- }
- }
- return ::new (Context) FormatAttr(Context, CI, Format, FormatIdx, FirstArg);
- }
- /// Handle __attribute__((format(type,idx,firstarg))) attributes based on
- /// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
- static void handleFormatAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
- // In C++ the implicit 'this' function parameter also counts, and they are
- // counted from one.
- bool HasImplicitThisParam = isInstanceMethod(D);
- unsigned NumArgs = getFunctionOrMethodNumParams(D) + HasImplicitThisParam;
- IdentifierInfo *II = AL.getArgAsIdent(0)->Ident;
- StringRef Format = II->getName();
- if (normalizeName(Format)) {
- // If we've modified the string name, we need a new identifier for it.
- II = &S.Context.Idents.get(Format);
- }
- // Check for supported formats.
- FormatAttrKind Kind = getFormatAttrKind(Format);
- if (Kind == IgnoredFormat)
- return;
- if (Kind == InvalidFormat) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
- << AL << II->getName();
- return;
- }
- // checks for the 2nd argument
- Expr *IdxExpr = AL.getArgAsExpr(1);
- uint32_t Idx;
- if (!checkUInt32Argument(S, AL, IdxExpr, Idx, 2))
- return;
- if (Idx < 1 || Idx > NumArgs) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << 2 << IdxExpr->getSourceRange();
- return;
- }
- // FIXME: Do we need to bounds check?
- unsigned ArgIdx = Idx - 1;
- if (HasImplicitThisParam) {
- if (ArgIdx == 0) {
- S.Diag(AL.getLoc(),
- diag::err_format_attribute_implicit_this_format_string)
- << IdxExpr->getSourceRange();
- return;
- }
- ArgIdx--;
- }
- // make sure the format string is really a string
- QualType Ty = getFunctionOrMethodParamType(D, ArgIdx);
- if (Kind == CFStringFormat) {
- if (!isCFStringType(Ty, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "a CFString" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, ArgIdx);
- return;
- }
- } else if (Kind == NSStringFormat) {
- // FIXME: do we need to check if the type is NSString*? What are the
- // semantics?
- if (!isNSStringType(Ty, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "an NSString" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, ArgIdx);
- return;
- }
- } else if (!Ty->isPointerType() ||
- !Ty->castAs<PointerType>()->getPointeeType()->isCharType()) {
- S.Diag(AL.getLoc(), diag::err_format_attribute_not)
- << "a string type" << IdxExpr->getSourceRange()
- << getFunctionOrMethodParamRange(D, ArgIdx);
- return;
- }
- // check the 3rd argument
- Expr *FirstArgExpr = AL.getArgAsExpr(2);
- uint32_t FirstArg;
- if (!checkUInt32Argument(S, AL, FirstArgExpr, FirstArg, 3))
- return;
- // check if the function is variadic if the 3rd argument non-zero
- if (FirstArg != 0) {
- if (isFunctionOrMethodVariadic(D)) {
- ++NumArgs; // +1 for ...
- } else {
- S.Diag(D->getLocation(), diag::err_format_attribute_requires_variadic);
- return;
- }
- }
- // strftime requires FirstArg to be 0 because it doesn't read from any
- // variable the input is just the current time + the format string.
- if (Kind == StrftimeFormat) {
- if (FirstArg != 0) {
- S.Diag(AL.getLoc(), diag::err_format_strftime_third_parameter)
- << FirstArgExpr->getSourceRange();
- return;
- }
- // if 0 it disables parameter checking (to use with e.g. va_list)
- } else if (FirstArg != 0 && FirstArg != NumArgs) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << 3 << FirstArgExpr->getSourceRange();
- return;
- }
- FormatAttr *NewAttr = S.mergeFormatAttr(D, AL, II, Idx, FirstArg);
- if (NewAttr)
- D->addAttr(NewAttr);
- }
- /// Handle __attribute__((callback(CalleeIdx, PayloadIdx0, ...))) attributes.
- static void handleCallbackAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // The index that identifies the callback callee is mandatory.
- if (AL.getNumArgs() == 0) {
- S.Diag(AL.getLoc(), diag::err_callback_attribute_no_callee)
- << AL.getRange();
- return;
- }
- bool HasImplicitThisParam = isInstanceMethod(D);
- int32_t NumArgs = getFunctionOrMethodNumParams(D);
- FunctionDecl *FD = D->getAsFunction();
- assert(FD && "Expected a function declaration!");
- llvm::StringMap<int> NameIdxMapping;
- NameIdxMapping["__"] = -1;
- NameIdxMapping["this"] = 0;
- int Idx = 1;
- for (const ParmVarDecl *PVD : FD->parameters())
- NameIdxMapping[PVD->getName()] = Idx++;
- auto UnknownName = NameIdxMapping.end();
- SmallVector<int, 8> EncodingIndices;
- for (unsigned I = 0, E = AL.getNumArgs(); I < E; ++I) {
- SourceRange SR;
- int32_t ArgIdx;
- if (AL.isArgIdent(I)) {
- IdentifierLoc *IdLoc = AL.getArgAsIdent(I);
- auto It = NameIdxMapping.find(IdLoc->Ident->getName());
- if (It == UnknownName) {
- S.Diag(AL.getLoc(), diag::err_callback_attribute_argument_unknown)
- << IdLoc->Ident << IdLoc->Loc;
- return;
- }
- SR = SourceRange(IdLoc->Loc);
- ArgIdx = It->second;
- } else if (AL.isArgExpr(I)) {
- Expr *IdxExpr = AL.getArgAsExpr(I);
- // If the expression is not parseable as an int32_t we have a problem.
- if (!checkUInt32Argument(S, AL, IdxExpr, (uint32_t &)ArgIdx, I + 1,
- false)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << (I + 1) << IdxExpr->getSourceRange();
- return;
- }
- // Check oob, excluding the special values, 0 and -1.
- if (ArgIdx < -1 || ArgIdx > NumArgs) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << (I + 1) << IdxExpr->getSourceRange();
- return;
- }
- SR = IdxExpr->getSourceRange();
- } else {
- llvm_unreachable("Unexpected ParsedAttr argument type!");
- }
- if (ArgIdx == 0 && !HasImplicitThisParam) {
- S.Diag(AL.getLoc(), diag::err_callback_implicit_this_not_available)
- << (I + 1) << SR;
- return;
- }
- // Adjust for the case we do not have an implicit "this" parameter. In this
- // case we decrease all positive values by 1 to get LLVM argument indices.
- if (!HasImplicitThisParam && ArgIdx > 0)
- ArgIdx -= 1;
- EncodingIndices.push_back(ArgIdx);
- }
- int CalleeIdx = EncodingIndices.front();
- // Check if the callee index is proper, thus not "this" and not "unknown".
- // This means the "CalleeIdx" has to be non-negative if "HasImplicitThisParam"
- // is false and positive if "HasImplicitThisParam" is true.
- if (CalleeIdx < (int)HasImplicitThisParam) {
- S.Diag(AL.getLoc(), diag::err_callback_attribute_invalid_callee)
- << AL.getRange();
- return;
- }
- // Get the callee type, note the index adjustment as the AST doesn't contain
- // the this type (which the callee cannot reference anyway!).
- const Type *CalleeType =
- getFunctionOrMethodParamType(D, CalleeIdx - HasImplicitThisParam)
- .getTypePtr();
- if (!CalleeType || !CalleeType->isFunctionPointerType()) {
- S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
- << AL.getRange();
- return;
- }
- const Type *CalleeFnType =
- CalleeType->getPointeeType()->getUnqualifiedDesugaredType();
- // TODO: Check the type of the callee arguments.
- const auto *CalleeFnProtoType = dyn_cast<FunctionProtoType>(CalleeFnType);
- if (!CalleeFnProtoType) {
- S.Diag(AL.getLoc(), diag::err_callback_callee_no_function_type)
- << AL.getRange();
- return;
- }
- if (CalleeFnProtoType->getNumParams() > EncodingIndices.size() - 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
- << AL << (unsigned)(EncodingIndices.size() - 1);
- return;
- }
- if (CalleeFnProtoType->getNumParams() < EncodingIndices.size() - 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments)
- << AL << (unsigned)(EncodingIndices.size() - 1);
- return;
- }
- if (CalleeFnProtoType->isVariadic()) {
- S.Diag(AL.getLoc(), diag::err_callback_callee_is_variadic) << AL.getRange();
- return;
- }
- // Do not allow multiple callback attributes.
- if (D->hasAttr<CallbackAttr>()) {
- S.Diag(AL.getLoc(), diag::err_callback_attribute_multiple) << AL.getRange();
- return;
- }
- D->addAttr(::new (S.Context) CallbackAttr(
- S.Context, AL, EncodingIndices.data(), EncodingIndices.size()));
- }
- static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Try to find the underlying union declaration.
- RecordDecl *RD = nullptr;
- const auto *TD = dyn_cast<TypedefNameDecl>(D);
- if (TD && TD->getUnderlyingType()->isUnionType())
- RD = TD->getUnderlyingType()->getAsUnionType()->getDecl();
- else
- RD = dyn_cast<RecordDecl>(D);
- if (!RD || !RD->isUnion()) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL
- << ExpectedUnion;
- return;
- }
- if (!RD->isCompleteDefinition()) {
- if (!RD->isBeingDefined())
- S.Diag(AL.getLoc(),
- diag::warn_transparent_union_attribute_not_definition);
- return;
- }
- RecordDecl::field_iterator Field = RD->field_begin(),
- FieldEnd = RD->field_end();
- if (Field == FieldEnd) {
- S.Diag(AL.getLoc(), diag::warn_transparent_union_attribute_zero_fields);
- return;
- }
- FieldDecl *FirstField = *Field;
- QualType FirstType = FirstField->getType();
- if (FirstType->hasFloatingRepresentation() || FirstType->isVectorType()) {
- S.Diag(FirstField->getLocation(),
- diag::warn_transparent_union_attribute_floating)
- << FirstType->isVectorType() << FirstType;
- return;
- }
- if (FirstType->isIncompleteType())
- return;
- uint64_t FirstSize = S.Context.getTypeSize(FirstType);
- uint64_t FirstAlign = S.Context.getTypeAlign(FirstType);
- for (; Field != FieldEnd; ++Field) {
- QualType FieldType = Field->getType();
- if (FieldType->isIncompleteType())
- return;
- // FIXME: this isn't fully correct; we also need to test whether the
- // members of the union would all have the same calling convention as the
- // first member of the union. Checking just the size and alignment isn't
- // sufficient (consider structs passed on the stack instead of in registers
- // as an example).
- if (S.Context.getTypeSize(FieldType) != FirstSize ||
- S.Context.getTypeAlign(FieldType) > FirstAlign) {
- // Warn if we drop the attribute.
- bool isSize = S.Context.getTypeSize(FieldType) != FirstSize;
- unsigned FieldBits = isSize? S.Context.getTypeSize(FieldType)
- : S.Context.getTypeAlign(FieldType);
- S.Diag(Field->getLocation(),
- diag::warn_transparent_union_attribute_field_size_align)
- << isSize << Field->getDeclName() << FieldBits;
- unsigned FirstBits = isSize? FirstSize : FirstAlign;
- S.Diag(FirstField->getLocation(),
- diag::note_transparent_union_first_field_size_align)
- << isSize << FirstBits;
- return;
- }
- }
- RD->addAttr(::new (S.Context) TransparentUnionAttr(S.Context, AL));
- }
- static void handleAnnotateAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Make sure that there is a string literal as the annotation's single
- // argument.
- StringRef Str;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str))
- return;
- // Don't duplicate annotations that are already set.
- for (const auto *I : D->specific_attrs<AnnotateAttr>()) {
- if (I->getAnnotation() == Str)
- return;
- }
- D->addAttr(::new (S.Context) AnnotateAttr(S.Context, AL, Str));
- }
- static void handleAlignValueAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- S.AddAlignValueAttr(D, AL, AL.getArgAsExpr(0));
- }
- void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) {
- AlignValueAttr TmpAttr(Context, CI, E);
- SourceLocation AttrLoc = CI.getLoc();
- QualType T;
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D))
- T = TD->getUnderlyingType();
- else if (const auto *VD = dyn_cast<ValueDecl>(D))
- T = VD->getType();
- else
- llvm_unreachable("Unknown decl type for align_value");
- if (!T->isDependentType() && !T->isAnyPointerType() &&
- !T->isReferenceType() && !T->isMemberPointerType()) {
- Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only)
- << &TmpAttr /*TmpAttr.getName()*/ << T << D->getSourceRange();
- return;
- }
- if (!E->isValueDependent()) {
- llvm::APSInt Alignment;
- ExprResult ICE
- = VerifyIntegerConstantExpression(E, &Alignment,
- diag::err_align_value_attribute_argument_not_int,
- /*AllowFold*/ false);
- if (ICE.isInvalid())
- return;
- if (!Alignment.isPowerOf2()) {
- Diag(AttrLoc, diag::err_alignment_not_power_of_two)
- << E->getSourceRange();
- return;
- }
- D->addAttr(::new (Context) AlignValueAttr(Context, CI, ICE.get()));
- return;
- }
- // Save dependent expressions in the AST to be instantiated.
- D->addAttr(::new (Context) AlignValueAttr(Context, CI, E));
- }
- static void handleAlignedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // check the attribute arguments.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
- return;
- }
- if (AL.getNumArgs() == 0) {
- D->addAttr(::new (S.Context) AlignedAttr(S.Context, AL, true, nullptr));
- return;
- }
- Expr *E = AL.getArgAsExpr(0);
- if (AL.isPackExpansion() && !E->containsUnexpandedParameterPack()) {
- S.Diag(AL.getEllipsisLoc(),
- diag::err_pack_expansion_without_parameter_packs);
- return;
- }
- if (!AL.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E))
- return;
- S.AddAlignedAttr(D, AL, E, AL.isPackExpansion());
- }
- void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E,
- bool IsPackExpansion) {
- AlignedAttr TmpAttr(Context, CI, true, E);
- SourceLocation AttrLoc = CI.getLoc();
- // C++11 alignas(...) and C11 _Alignas(...) have additional requirements.
- if (TmpAttr.isAlignas()) {
- // C++11 [dcl.align]p1:
- // An alignment-specifier may be applied to a variable or to a class
- // data member, but it shall not be applied to a bit-field, a function
- // parameter, the formal parameter of a catch clause, or a variable
- // declared with the register storage class specifier. An
- // alignment-specifier may also be applied to the declaration of a class
- // or enumeration type.
- // C11 6.7.5/2:
- // An alignment attribute shall not be specified in a declaration of
- // a typedef, or a bit-field, or a function, or a parameter, or an
- // object declared with the register storage-class specifier.
- int DiagKind = -1;
- if (isa<ParmVarDecl>(D)) {
- DiagKind = 0;
- } else if (const auto *VD = dyn_cast<VarDecl>(D)) {
- if (VD->getStorageClass() == SC_Register)
- DiagKind = 1;
- if (VD->isExceptionVariable())
- DiagKind = 2;
- } else if (const auto *FD = dyn_cast<FieldDecl>(D)) {
- if (FD->isBitField())
- DiagKind = 3;
- } else if (!isa<TagDecl>(D)) {
- Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr
- << (TmpAttr.isC11() ? ExpectedVariableOrField
- : ExpectedVariableFieldOrTag);
- return;
- }
- if (DiagKind != -1) {
- Diag(AttrLoc, diag::err_alignas_attribute_wrong_decl_type)
- << &TmpAttr << DiagKind;
- return;
- }
- }
- if (E->isValueDependent()) {
- // We can't support a dependent alignment on a non-dependent type,
- // because we have no way to model that a type is "alignment-dependent"
- // but not dependent in any other way.
- if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) {
- if (!TND->getUnderlyingType()->isDependentType()) {
- Diag(AttrLoc, diag::err_alignment_dependent_typedef_name)
- << E->getSourceRange();
- return;
- }
- }
- // Save dependent expressions in the AST to be instantiated.
- AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, E);
- AA->setPackExpansion(IsPackExpansion);
- D->addAttr(AA);
- return;
- }
- // FIXME: Cache the number on the AL object?
- llvm::APSInt Alignment;
- ExprResult ICE
- = VerifyIntegerConstantExpression(E, &Alignment,
- diag::err_aligned_attribute_argument_not_int,
- /*AllowFold*/ false);
- if (ICE.isInvalid())
- return;
- uint64_t AlignVal = Alignment.getZExtValue();
- // C++11 [dcl.align]p2:
- // -- if the constant expression evaluates to zero, the alignment
- // specifier shall have no effect
- // C11 6.7.5p6:
- // An alignment specification of zero has no effect.
- if (!(TmpAttr.isAlignas() && !Alignment)) {
- if (!llvm::isPowerOf2_64(AlignVal)) {
- Diag(AttrLoc, diag::err_alignment_not_power_of_two)
- << E->getSourceRange();
- return;
- }
- }
- // Alignment calculations can wrap around if it's greater than 2**28.
- unsigned MaxValidAlignment =
- Context.getTargetInfo().getTriple().isOSBinFormatCOFF() ? 8192
- : 268435456;
- if (AlignVal > MaxValidAlignment) {
- Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaxValidAlignment
- << E->getSourceRange();
- return;
- }
- if (Context.getTargetInfo().isTLSSupported()) {
- unsigned MaxTLSAlign =
- Context.toCharUnitsFromBits(Context.getTargetInfo().getMaxTLSAlign())
- .getQuantity();
- const auto *VD = dyn_cast<VarDecl>(D);
- if (MaxTLSAlign && AlignVal > MaxTLSAlign && VD &&
- VD->getTLSKind() != VarDecl::TLS_None) {
- Diag(VD->getLocation(), diag::err_tls_var_aligned_over_maximum)
- << (unsigned)AlignVal << VD << MaxTLSAlign;
- return;
- }
- }
- AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, true, ICE.get());
- AA->setPackExpansion(IsPackExpansion);
- D->addAttr(AA);
- }
- void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI,
- TypeSourceInfo *TS, bool IsPackExpansion) {
- // FIXME: Cache the number on the AL object if non-dependent?
- // FIXME: Perform checking of type validity
- AlignedAttr *AA = ::new (Context) AlignedAttr(Context, CI, false, TS);
- AA->setPackExpansion(IsPackExpansion);
- D->addAttr(AA);
- }
- void Sema::CheckAlignasUnderalignment(Decl *D) {
- assert(D->hasAttrs() && "no attributes on decl");
- QualType UnderlyingTy, DiagTy;
- if (const auto *VD = dyn_cast<ValueDecl>(D)) {
- UnderlyingTy = DiagTy = VD->getType();
- } else {
- UnderlyingTy = DiagTy = Context.getTagDeclType(cast<TagDecl>(D));
- if (const auto *ED = dyn_cast<EnumDecl>(D))
- UnderlyingTy = ED->getIntegerType();
- }
- if (DiagTy->isDependentType() || DiagTy->isIncompleteType())
- return;
- // C++11 [dcl.align]p5, C11 6.7.5/4:
- // The combined effect of all alignment attributes in a declaration shall
- // not specify an alignment that is less strict than the alignment that
- // would otherwise be required for the entity being declared.
- AlignedAttr *AlignasAttr = nullptr;
- unsigned Align = 0;
- for (auto *I : D->specific_attrs<AlignedAttr>()) {
- if (I->isAlignmentDependent())
- return;
- if (I->isAlignas())
- AlignasAttr = I;
- Align = std::max(Align, I->getAlignment(Context));
- }
- if (AlignasAttr && Align) {
- CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align);
- CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy);
- if (NaturalAlign > RequestedAlign)
- Diag(AlignasAttr->getLocation(), diag::err_alignas_underaligned)
- << DiagTy << (unsigned)NaturalAlign.getQuantity();
- }
- }
- bool Sema::checkMSInheritanceAttrOnDefinition(
- CXXRecordDecl *RD, SourceRange Range, bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling) {
- assert(RD->hasDefinition() && "RD has no definition!");
- // We may not have seen base specifiers or any virtual methods yet. We will
- // have to wait until the record is defined to catch any mismatches.
- if (!RD->getDefinition()->isCompleteDefinition())
- return false;
- // The unspecified model never matches what a definition could need.
- if (SemanticSpelling == MSInheritanceAttr::Keyword_unspecified_inheritance)
- return false;
- if (BestCase) {
- if (RD->calculateInheritanceModel() == SemanticSpelling)
- return false;
- } else {
- if (RD->calculateInheritanceModel() <= SemanticSpelling)
- return false;
- }
- Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance)
- << 0 /*definition*/;
- Diag(RD->getDefinition()->getLocation(), diag::note_defined_here)
- << RD->getNameAsString();
- return true;
- }
- /// parseModeAttrArg - Parses attribute mode string and returns parsed type
- /// attribute.
- static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
- bool &IntegerMode, bool &ComplexMode) {
- IntegerMode = true;
- ComplexMode = false;
- switch (Str.size()) {
- case 2:
- switch (Str[0]) {
- case 'Q':
- DestWidth = 8;
- break;
- case 'H':
- DestWidth = 16;
- break;
- case 'S':
- DestWidth = 32;
- break;
- case 'D':
- DestWidth = 64;
- break;
- case 'X':
- DestWidth = 96;
- break;
- case 'T':
- DestWidth = 128;
- break;
- }
- if (Str[1] == 'F') {
- IntegerMode = false;
- } else if (Str[1] == 'C') {
- IntegerMode = false;
- ComplexMode = true;
- } else if (Str[1] != 'I') {
- DestWidth = 0;
- }
- break;
- case 4:
- // FIXME: glibc uses 'word' to define register_t; this is narrower than a
- // pointer on PIC16 and other embedded platforms.
- if (Str == "word")
- DestWidth = S.Context.getTargetInfo().getRegisterWidth();
- else if (Str == "byte")
- DestWidth = S.Context.getTargetInfo().getCharWidth();
- break;
- case 7:
- if (Str == "pointer")
- DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
- break;
- case 11:
- if (Str == "unwind_word")
- DestWidth = S.Context.getTargetInfo().getUnwindWordWidth();
- break;
- }
- }
- /// handleModeAttr - This attribute modifies the width of a decl with primitive
- /// type.
- ///
- /// Despite what would be logical, the mode attribute is a decl attribute, not a
- /// type attribute: 'int ** __attribute((mode(HI))) *G;' tries to make 'G' be
- /// HImode, not an intermediate pointer.
- static void handleModeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // This attribute isn't documented, but glibc uses it. It changes
- // the width of an int or unsigned int to the specified size.
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIdentifier;
- return;
- }
- IdentifierInfo *Name = AL.getArgAsIdent(0)->Ident;
- S.AddModeAttr(D, AL, Name);
- }
- void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI,
- IdentifierInfo *Name, bool InInstantiation) {
- StringRef Str = Name->getName();
- normalizeName(Str);
- SourceLocation AttrLoc = CI.getLoc();
- unsigned DestWidth = 0;
- bool IntegerMode = true;
- bool ComplexMode = false;
- llvm::APInt VectorSize(64, 0);
- if (Str.size() >= 4 && Str[0] == 'V') {
- // Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2).
- size_t StrSize = Str.size();
- size_t VectorStringLength = 0;
- while ((VectorStringLength + 1) < StrSize &&
- isdigit(Str[VectorStringLength + 1]))
- ++VectorStringLength;
- if (VectorStringLength &&
- !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) &&
- VectorSize.isPowerOf2()) {
- parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth,
- IntegerMode, ComplexMode);
- // Avoid duplicate warning from template instantiation.
- if (!InInstantiation)
- Diag(AttrLoc, diag::warn_vector_mode_deprecated);
- } else {
- VectorSize = 0;
- }
- }
- if (!VectorSize)
- parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode);
- // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
- // and friends, at least with glibc.
- // FIXME: Make sure floating-point mappings are accurate
- // FIXME: Support XF and TF types
- if (!DestWidth) {
- Diag(AttrLoc, diag::err_machine_mode) << 0 /*Unknown*/ << Name;
- return;
- }
- QualType OldTy;
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D))
- OldTy = TD->getUnderlyingType();
- else if (const auto *ED = dyn_cast<EnumDecl>(D)) {
- // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'.
- // Try to get type from enum declaration, default to int.
- OldTy = ED->getIntegerType();
- if (OldTy.isNull())
- OldTy = Context.IntTy;
- } else
- OldTy = cast<ValueDecl>(D)->getType();
- if (OldTy->isDependentType()) {
- D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
- return;
- }
- // Base type can also be a vector type (see PR17453).
- // Distinguish between base type and base element type.
- QualType OldElemTy = OldTy;
- if (const auto *VT = OldTy->getAs<VectorType>())
- OldElemTy = VT->getElementType();
- // GCC allows 'mode' attribute on enumeration types (even incomplete), except
- // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete
- // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected.
- if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
- VectorSize.getBoolValue()) {
- Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange();
- return;
- }
- bool IntegralOrAnyEnumType =
- OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs<EnumType>();
- if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() &&
- !IntegralOrAnyEnumType)
- Diag(AttrLoc, diag::err_mode_not_primitive);
- else if (IntegerMode) {
- if (!IntegralOrAnyEnumType)
- Diag(AttrLoc, diag::err_mode_wrong_type);
- } else if (ComplexMode) {
- if (!OldElemTy->isComplexType())
- Diag(AttrLoc, diag::err_mode_wrong_type);
- } else {
- if (!OldElemTy->isFloatingType())
- Diag(AttrLoc, diag::err_mode_wrong_type);
- }
- QualType NewElemTy;
- if (IntegerMode)
- NewElemTy = Context.getIntTypeForBitwidth(DestWidth,
- OldElemTy->isSignedIntegerType());
- else
- NewElemTy = Context.getRealTypeForBitwidth(DestWidth);
- if (NewElemTy.isNull()) {
- Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
- return;
- }
- if (ComplexMode) {
- NewElemTy = Context.getComplexType(NewElemTy);
- }
- QualType NewTy = NewElemTy;
- if (VectorSize.getBoolValue()) {
- NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(),
- VectorType::GenericVector);
- } else if (const auto *OldVT = OldTy->getAs<VectorType>()) {
- // Complex machine mode does not support base vector types.
- if (ComplexMode) {
- Diag(AttrLoc, diag::err_complex_mode_vector_type);
- return;
- }
- unsigned NumElements = Context.getTypeSize(OldElemTy) *
- OldVT->getNumElements() /
- Context.getTypeSize(NewElemTy);
- NewTy =
- Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind());
- }
- if (NewTy.isNull()) {
- Diag(AttrLoc, diag::err_mode_wrong_type);
- return;
- }
- // Install the new type.
- if (auto *TD = dyn_cast<TypedefNameDecl>(D))
- TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy);
- else if (auto *ED = dyn_cast<EnumDecl>(D))
- ED->setIntegerType(NewTy);
- else
- cast<ValueDecl>(D)->setType(NewTy);
- D->addAttr(::new (Context) ModeAttr(Context, CI, Name));
- }
- static void handleNoDebugAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- D->addAttr(::new (S.Context) NoDebugAttr(S.Context, AL));
- }
- AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D,
- const AttributeCommonInfo &CI,
- const IdentifierInfo *Ident) {
- if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
- Diag(CI.getLoc(), diag::warn_attribute_ignored) << Ident;
- Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
- return nullptr;
- }
- if (D->hasAttr<AlwaysInlineAttr>())
- return nullptr;
- return ::new (Context) AlwaysInlineAttr(Context, CI);
- }
- CommonAttr *Sema::mergeCommonAttr(Decl *D, const ParsedAttr &AL) {
- if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
- return nullptr;
- return ::new (Context) CommonAttr(Context, AL);
- }
- CommonAttr *Sema::mergeCommonAttr(Decl *D, const CommonAttr &AL) {
- if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
- return nullptr;
- return ::new (Context) CommonAttr(Context, AL);
- }
- InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
- const ParsedAttr &AL) {
- if (const auto *VD = dyn_cast<VarDecl>(D)) {
- // Attribute applies to Var but not any subclass of it (like ParmVar,
- // ImplicitParm or VarTemplateSpecialization).
- if (VD->getKind() != Decl::Var) {
- Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
- : ExpectedVariableOrFunction);
- return nullptr;
- }
- // Attribute does not apply to non-static local variables.
- if (VD->hasLocalStorage()) {
- Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage);
- return nullptr;
- }
- }
- if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
- return nullptr;
- return ::new (Context) InternalLinkageAttr(Context, AL);
- }
- InternalLinkageAttr *
- Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) {
- if (const auto *VD = dyn_cast<VarDecl>(D)) {
- // Attribute applies to Var but not any subclass of it (like ParmVar,
- // ImplicitParm or VarTemplateSpecialization).
- if (VD->getKind() != Decl::Var) {
- Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type)
- << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass
- : ExpectedVariableOrFunction);
- return nullptr;
- }
- // Attribute does not apply to non-static local variables.
- if (VD->hasLocalStorage()) {
- Diag(VD->getLocation(), diag::warn_internal_linkage_local_storage);
- return nullptr;
- }
- }
- if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
- return nullptr;
- return ::new (Context) InternalLinkageAttr(Context, AL);
- }
- MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) {
- if (OptimizeNoneAttr *Optnone = D->getAttr<OptimizeNoneAttr>()) {
- Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'minsize'";
- Diag(Optnone->getLocation(), diag::note_conflicting_attribute);
- return nullptr;
- }
- if (D->hasAttr<MinSizeAttr>())
- return nullptr;
- return ::new (Context) MinSizeAttr(Context, CI);
- }
- NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
- Decl *D, const NoSpeculativeLoadHardeningAttr &AL) {
- if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL))
- return nullptr;
- return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL);
- }
- OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
- const AttributeCommonInfo &CI) {
- if (AlwaysInlineAttr *Inline = D->getAttr<AlwaysInlineAttr>()) {
- Diag(Inline->getLocation(), diag::warn_attribute_ignored) << Inline;
- Diag(CI.getLoc(), diag::note_conflicting_attribute);
- D->dropAttr<AlwaysInlineAttr>();
- }
- if (MinSizeAttr *MinSize = D->getAttr<MinSizeAttr>()) {
- Diag(MinSize->getLocation(), diag::warn_attribute_ignored) << MinSize;
- Diag(CI.getLoc(), diag::note_conflicting_attribute);
- D->dropAttr<MinSizeAttr>();
- }
- if (D->hasAttr<OptimizeNoneAttr>())
- return nullptr;
- return ::new (Context) OptimizeNoneAttr(Context, CI);
- }
- SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
- Decl *D, const SpeculativeLoadHardeningAttr &AL) {
- if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL))
- return nullptr;
- return ::new (Context) SpeculativeLoadHardeningAttr(Context, AL);
- }
- static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL))
- return;
- if (AlwaysInlineAttr *Inline =
- S.mergeAlwaysInlineAttr(D, AL, AL.getAttrName()))
- D->addAttr(Inline);
- }
- static void handleMinSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (MinSizeAttr *MinSize = S.mergeMinSizeAttr(D, AL))
- D->addAttr(MinSize);
- }
- static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (OptimizeNoneAttr *Optnone = S.mergeOptimizeNoneAttr(D, AL))
- D->addAttr(Optnone);
- }
- static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL))
- return;
- const auto *VD = cast<VarDecl>(D);
- if (!VD->hasGlobalStorage()) {
- S.Diag(AL.getLoc(), diag::err_cuda_nonglobal_constant);
- return;
- }
- D->addAttr(::new (S.Context) CUDAConstantAttr(S.Context, AL));
- }
- static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL))
- return;
- const auto *VD = cast<VarDecl>(D);
- // extern __shared__ is only allowed on arrays with no length (e.g.
- // "int x[]").
- if (!S.getLangOpts().GPURelocatableDeviceCode && VD->hasExternalStorage() &&
- !isa<IncompleteArrayType>(VD->getType())) {
- S.Diag(AL.getLoc(), diag::err_cuda_extern_shared) << VD;
- return;
- }
- if (S.getLangOpts().CUDA && VD->hasLocalStorage() &&
- S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared)
- << S.CurrentCUDATarget())
- return;
- D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL));
- }
- static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, AL) ||
- checkAttrMutualExclusion<CUDAHostAttr>(S, D, AL)) {
- return;
- }
- const auto *FD = cast<FunctionDecl>(D);
- if (!FD->getReturnType()->isVoidType() &&
- !FD->getReturnType()->getAs<AutoType>() &&
- !FD->getReturnType()->isInstantiationDependentType()) {
- SourceRange RTRange = FD->getReturnTypeSourceRange();
- S.Diag(FD->getTypeSpecStartLoc(), diag::err_kern_type_not_void_return)
- << FD->getType()
- << (RTRange.isValid() ? FixItHint::CreateReplacement(RTRange, "void")
- : FixItHint());
- return;
- }
- if (const auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
- if (Method->isInstance()) {
- S.Diag(Method->getBeginLoc(), diag::err_kern_is_nonstatic_method)
- << Method;
- return;
- }
- S.Diag(Method->getBeginLoc(), diag::warn_kern_is_method) << Method;
- }
- // Only warn for "inline" when compiling for host, to cut down on noise.
- if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice)
- S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD;
- D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL));
- }
- static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- const auto *Fn = cast<FunctionDecl>(D);
- if (!Fn->isInlineSpecified()) {
- S.Diag(AL.getLoc(), diag::warn_gnu_inline_attribute_requires_inline);
- return;
- }
- if (S.LangOpts.CPlusPlus && Fn->getStorageClass() != SC_Extern)
- S.Diag(AL.getLoc(), diag::warn_gnu_inline_cplusplus_without_extern);
- D->addAttr(::new (S.Context) GNUInlineAttr(S.Context, AL));
- }
- static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (hasDeclarator(D)) return;
- // Diagnostic is emitted elsewhere: here we store the (valid) AL
- // in the Decl node for syntactic reasoning, e.g., pretty-printing.
- CallingConv CC;
- if (S.CheckCallingConvAttr(AL, CC, /*FD*/nullptr))
- return;
- if (!isa<ObjCMethodDecl>(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << ExpectedFunctionOrMethod;
- return;
- }
- switch (AL.getKind()) {
- case ParsedAttr::AT_FastCall:
- D->addAttr(::new (S.Context) FastCallAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_StdCall:
- D->addAttr(::new (S.Context) StdCallAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_ThisCall:
- D->addAttr(::new (S.Context) ThisCallAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_CDecl:
- D->addAttr(::new (S.Context) CDeclAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_Pascal:
- D->addAttr(::new (S.Context) PascalAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_SwiftCall:
- D->addAttr(::new (S.Context) SwiftCallAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_VectorCall:
- D->addAttr(::new (S.Context) VectorCallAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_MSABI:
- D->addAttr(::new (S.Context) MSABIAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_SysVABI:
- D->addAttr(::new (S.Context) SysVABIAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_RegCall:
- D->addAttr(::new (S.Context) RegCallAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_Pcs: {
- PcsAttr::PCSType PCS;
- switch (CC) {
- case CC_AAPCS:
- PCS = PcsAttr::AAPCS;
- break;
- case CC_AAPCS_VFP:
- PCS = PcsAttr::AAPCS_VFP;
- break;
- default:
- llvm_unreachable("unexpected calling convention in pcs attribute");
- }
- D->addAttr(::new (S.Context) PcsAttr(S.Context, AL, PCS));
- return;
- }
- case ParsedAttr::AT_AArch64VectorPcs:
- D->addAttr(::new (S.Context) AArch64VectorPcsAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_IntelOclBicc:
- D->addAttr(::new (S.Context) IntelOclBiccAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_PreserveMost:
- D->addAttr(::new (S.Context) PreserveMostAttr(S.Context, AL));
- return;
- case ParsedAttr::AT_PreserveAll:
- D->addAttr(::new (S.Context) PreserveAllAttr(S.Context, AL));
- return;
- default:
- llvm_unreachable("unexpected attribute kind");
- }
- }
- static void handleSuppressAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- std::vector<StringRef> DiagnosticIdentifiers;
- for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
- StringRef RuleName;
- if (!S.checkStringLiteralArgumentAttr(AL, I, RuleName, nullptr))
- return;
- // FIXME: Warn if the rule name is unknown. This is tricky because only
- // clang-tidy knows about available rules.
- DiagnosticIdentifiers.push_back(RuleName);
- }
- D->addAttr(::new (S.Context)
- SuppressAttr(S.Context, AL, DiagnosticIdentifiers.data(),
- DiagnosticIdentifiers.size()));
- }
- static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- TypeSourceInfo *DerefTypeLoc = nullptr;
- QualType ParmType;
- if (AL.hasParsedType()) {
- ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc);
- unsigned SelectIdx = ~0U;
- if (ParmType->isVoidType())
- SelectIdx = 0;
- else if (ParmType->isReferenceType())
- SelectIdx = 1;
- else if (ParmType->isArrayType())
- SelectIdx = 2;
- if (SelectIdx != ~0U) {
- S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument)
- << SelectIdx << AL;
- return;
- }
- }
- // To check if earlier decl attributes do not conflict the newly parsed ones
- // we always add (and check) the attribute to the cannonical decl.
- D = D->getCanonicalDecl();
- if (AL.getKind() == ParsedAttr::AT_Owner) {
- if (checkAttrMutualExclusion<PointerAttr>(S, D, AL))
- return;
- if (const auto *OAttr = D->getAttr<OwnerAttr>()) {
- const Type *ExistingDerefType = OAttr->getDerefTypeLoc()
- ? OAttr->getDerefType().getTypePtr()
- : nullptr;
- if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
- << AL << OAttr;
- S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute);
- }
- return;
- }
- for (Decl *Redecl : D->redecls()) {
- Redecl->addAttr(::new (S.Context) OwnerAttr(S.Context, AL, DerefTypeLoc));
- }
- } else {
- if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL))
- return;
- if (const auto *PAttr = D->getAttr<PointerAttr>()) {
- const Type *ExistingDerefType = PAttr->getDerefTypeLoc()
- ? PAttr->getDerefType().getTypePtr()
- : nullptr;
- if (ExistingDerefType != ParmType.getTypePtrOrNull()) {
- S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)
- << AL << PAttr;
- S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute);
- }
- return;
- }
- for (Decl *Redecl : D->redecls()) {
- Redecl->addAttr(::new (S.Context)
- PointerAttr(S.Context, AL, DerefTypeLoc));
- }
- }
- }
- bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC,
- const FunctionDecl *FD) {
- if (Attrs.isInvalid())
- return true;
- if (Attrs.hasProcessingCache()) {
- CC = (CallingConv) Attrs.getProcessingCache();
- return false;
- }
- unsigned ReqArgs = Attrs.getKind() == ParsedAttr::AT_Pcs ? 1 : 0;
- if (!checkAttributeNumArgs(*this, Attrs, ReqArgs)) {
- Attrs.setInvalid();
- return true;
- }
- // TODO: diagnose uses of these conventions on the wrong target.
- switch (Attrs.getKind()) {
- case ParsedAttr::AT_CDecl:
- CC = CC_C;
- break;
- case ParsedAttr::AT_FastCall:
- CC = CC_X86FastCall;
- break;
- case ParsedAttr::AT_StdCall:
- CC = CC_X86StdCall;
- break;
- case ParsedAttr::AT_ThisCall:
- CC = CC_X86ThisCall;
- break;
- case ParsedAttr::AT_Pascal:
- CC = CC_X86Pascal;
- break;
- case ParsedAttr::AT_SwiftCall:
- CC = CC_Swift;
- break;
- case ParsedAttr::AT_VectorCall:
- CC = CC_X86VectorCall;
- break;
- case ParsedAttr::AT_AArch64VectorPcs:
- CC = CC_AArch64VectorCall;
- break;
- case ParsedAttr::AT_RegCall:
- CC = CC_X86RegCall;
- break;
- case ParsedAttr::AT_MSABI:
- CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
- CC_Win64;
- break;
- case ParsedAttr::AT_SysVABI:
- CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV :
- CC_C;
- break;
- case ParsedAttr::AT_Pcs: {
- StringRef StrRef;
- if (!checkStringLiteralArgumentAttr(Attrs, 0, StrRef)) {
- Attrs.setInvalid();
- return true;
- }
- if (StrRef == "aapcs") {
- CC = CC_AAPCS;
- break;
- } else if (StrRef == "aapcs-vfp") {
- CC = CC_AAPCS_VFP;
- break;
- }
- Attrs.setInvalid();
- Diag(Attrs.getLoc(), diag::err_invalid_pcs);
- return true;
- }
- case ParsedAttr::AT_IntelOclBicc:
- CC = CC_IntelOclBicc;
- break;
- case ParsedAttr::AT_PreserveMost:
- CC = CC_PreserveMost;
- break;
- case ParsedAttr::AT_PreserveAll:
- CC = CC_PreserveAll;
- break;
- default: llvm_unreachable("unexpected attribute kind");
- }
- TargetInfo::CallingConvCheckResult A = TargetInfo::CCCR_OK;
- const TargetInfo &TI = Context.getTargetInfo();
- // CUDA functions may have host and/or device attributes which indicate
- // their targeted execution environment, therefore the calling convention
- // of functions in CUDA should be checked against the target deduced based
- // on their host/device attributes.
- if (LangOpts.CUDA) {
- auto *Aux = Context.getAuxTargetInfo();
- auto CudaTarget = IdentifyCUDATarget(FD);
- bool CheckHost = false, CheckDevice = false;
- switch (CudaTarget) {
- case CFT_HostDevice:
- CheckHost = true;
- CheckDevice = true;
- break;
- case CFT_Host:
- CheckHost = true;
- break;
- case CFT_Device:
- case CFT_Global:
- CheckDevice = true;
- break;
- case CFT_InvalidTarget:
- llvm_unreachable("unexpected cuda target");
- }
- auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI;
- auto *DeviceTI = LangOpts.CUDAIsDevice ? &TI : Aux;
- if (CheckHost && HostTI)
- A = HostTI->checkCallingConvention(CC);
- if (A == TargetInfo::CCCR_OK && CheckDevice && DeviceTI)
- A = DeviceTI->checkCallingConvention(CC);
- } else {
- A = TI.checkCallingConvention(CC);
- }
- switch (A) {
- case TargetInfo::CCCR_OK:
- break;
- case TargetInfo::CCCR_Ignore:
- // Treat an ignored convention as if it was an explicit C calling convention
- // attribute. For example, __stdcall on Win x64 functions as __cdecl, so
- // that command line flags that change the default convention to
- // __vectorcall don't affect declarations marked __stdcall.
- CC = CC_C;
- break;
- case TargetInfo::CCCR_Error:
- Diag(Attrs.getLoc(), diag::error_cconv_unsupported)
- << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
- break;
- case TargetInfo::CCCR_Warning: {
- Diag(Attrs.getLoc(), diag::warn_cconv_unsupported)
- << Attrs << (int)CallingConventionIgnoredReason::ForThisTarget;
- // This convention is not valid for the target. Use the default function or
- // method calling convention.
- bool IsCXXMethod = false, IsVariadic = false;
- if (FD) {
- IsCXXMethod = FD->isCXXInstanceMember();
- IsVariadic = FD->isVariadic();
- }
- CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod);
- break;
- }
- }
- Attrs.setProcessingCache((unsigned) CC);
- return false;
- }
- /// Pointer-like types in the default address space.
- static bool isValidSwiftContextType(QualType Ty) {
- if (!Ty->hasPointerRepresentation())
- return Ty->isDependentType();
- return Ty->getPointeeType().getAddressSpace() == LangAS::Default;
- }
- /// Pointers and references in the default address space.
- static bool isValidSwiftIndirectResultType(QualType Ty) {
- if (const auto *PtrType = Ty->getAs<PointerType>()) {
- Ty = PtrType->getPointeeType();
- } else if (const auto *RefType = Ty->getAs<ReferenceType>()) {
- Ty = RefType->getPointeeType();
- } else {
- return Ty->isDependentType();
- }
- return Ty.getAddressSpace() == LangAS::Default;
- }
- /// Pointers and references to pointers in the default address space.
- static bool isValidSwiftErrorResultType(QualType Ty) {
- if (const auto *PtrType = Ty->getAs<PointerType>()) {
- Ty = PtrType->getPointeeType();
- } else if (const auto *RefType = Ty->getAs<ReferenceType>()) {
- Ty = RefType->getPointeeType();
- } else {
- return Ty->isDependentType();
- }
- if (!Ty.getQualifiers().empty())
- return false;
- return isValidSwiftContextType(Ty);
- }
- void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI,
- ParameterABI abi) {
- QualType type = cast<ParmVarDecl>(D)->getType();
- if (auto existingAttr = D->getAttr<ParameterABIAttr>()) {
- if (existingAttr->getABI() != abi) {
- Diag(CI.getLoc(), diag::err_attributes_are_not_compatible)
- << getParameterABISpelling(abi) << existingAttr;
- Diag(existingAttr->getLocation(), diag::note_conflicting_attribute);
- return;
- }
- }
- switch (abi) {
- case ParameterABI::Ordinary:
- llvm_unreachable("explicit attribute for ordinary parameter ABI?");
- case ParameterABI::SwiftContext:
- if (!isValidSwiftContextType(type)) {
- Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi) << /*pointer to pointer */ 0 << type;
- }
- D->addAttr(::new (Context) SwiftContextAttr(Context, CI));
- return;
- case ParameterABI::SwiftErrorResult:
- if (!isValidSwiftErrorResultType(type)) {
- Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi) << /*pointer to pointer */ 1 << type;
- }
- D->addAttr(::new (Context) SwiftErrorResultAttr(Context, CI));
- return;
- case ParameterABI::SwiftIndirectResult:
- if (!isValidSwiftIndirectResultType(type)) {
- Diag(CI.getLoc(), diag::err_swift_abi_parameter_wrong_type)
- << getParameterABISpelling(abi) << /*pointer*/ 0 << type;
- }
- D->addAttr(::new (Context) SwiftIndirectResultAttr(Context, CI));
- return;
- }
- llvm_unreachable("bad parameter ABI attribute");
- }
- /// Checks a regparm attribute, returning true if it is ill-formed and
- /// otherwise setting numParams to the appropriate value.
- bool Sema::CheckRegparmAttr(const ParsedAttr &AL, unsigned &numParams) {
- if (AL.isInvalid())
- return true;
- if (!checkAttributeNumArgs(*this, AL, 1)) {
- AL.setInvalid();
- return true;
- }
- uint32_t NP;
- Expr *NumParamsExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(*this, AL, NumParamsExpr, NP)) {
- AL.setInvalid();
- return true;
- }
- if (Context.getTargetInfo().getRegParmMax() == 0) {
- Diag(AL.getLoc(), diag::err_attribute_regparm_wrong_platform)
- << NumParamsExpr->getSourceRange();
- AL.setInvalid();
- return true;
- }
- numParams = NP;
- if (numParams > Context.getTargetInfo().getRegParmMax()) {
- Diag(AL.getLoc(), diag::err_attribute_regparm_invalid_number)
- << Context.getTargetInfo().getRegParmMax() << NumParamsExpr->getSourceRange();
- AL.setInvalid();
- return true;
- }
- return false;
- }
- // Checks whether an argument of launch_bounds attribute is
- // acceptable, performs implicit conversion to Rvalue, and returns
- // non-nullptr Expr result on success. Otherwise, it returns nullptr
- // and may output an error.
- static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E,
- const CUDALaunchBoundsAttr &AL,
- const unsigned Idx) {
- if (S.DiagnoseUnexpandedParameterPack(E))
- return nullptr;
- // Accept template arguments for now as they depend on something else.
- // We'll get to check them when they eventually get instantiated.
- if (E->isValueDependent())
- return E;
- llvm::APSInt I(64);
- if (!E->isIntegerConstantExpr(I, S.Context)) {
- S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type)
- << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange();
- return nullptr;
- }
- // Make sure we can fit it in 32 bits.
- if (!I.isIntN(32)) {
- S.Diag(E->getExprLoc(), diag::err_ice_too_large) << I.toString(10, false)
- << 32 << /* Unsigned */ 1;
- return nullptr;
- }
- if (I < 0)
- S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative)
- << &AL << Idx << E->getSourceRange();
- // We may need to perform implicit conversion of the argument.
- InitializedEntity Entity = InitializedEntity::InitializeParameter(
- S.Context, S.Context.getConstType(S.Context.IntTy), /*consume*/ false);
- ExprResult ValArg = S.PerformCopyInitialization(Entity, SourceLocation(), E);
- assert(!ValArg.isInvalid() &&
- "Unexpected PerformCopyInitialization() failure.");
- return ValArg.getAs<Expr>();
- }
- void Sema::AddLaunchBoundsAttr(Decl *D, const AttributeCommonInfo &CI,
- Expr *MaxThreads, Expr *MinBlocks) {
- CUDALaunchBoundsAttr TmpAttr(Context, CI, MaxThreads, MinBlocks);
- MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0);
- if (MaxThreads == nullptr)
- return;
- if (MinBlocks) {
- MinBlocks = makeLaunchBoundsArgExpr(*this, MinBlocks, TmpAttr, 1);
- if (MinBlocks == nullptr)
- return;
- }
- D->addAttr(::new (Context)
- CUDALaunchBoundsAttr(Context, CI, MaxThreads, MinBlocks));
- }
- static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1) ||
- !checkAttributeAtMostNumArgs(S, AL, 2))
- return;
- S.AddLaunchBoundsAttr(D, AL, AL.getArgAsExpr(0),
- AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr);
- }
- static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << /* arg num = */ 1 << AANT_ArgumentIdentifier;
- return;
- }
- ParamIdx ArgumentIdx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 2, AL.getArgAsExpr(1),
- ArgumentIdx))
- return;
- ParamIdx TypeTagIdx;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 3, AL.getArgAsExpr(2),
- TypeTagIdx))
- return;
- bool IsPointer = AL.getAttrName()->getName() == "pointer_with_type_tag";
- if (IsPointer) {
- // Ensure that buffer has a pointer type.
- unsigned ArgumentIdxAST = ArgumentIdx.getASTIndex();
- if (ArgumentIdxAST >= getFunctionOrMethodNumParams(D) ||
- !getFunctionOrMethodParamType(D, ArgumentIdxAST)->isPointerType())
- S.Diag(AL.getLoc(), diag::err_attribute_pointers_only) << AL << 0;
- }
- D->addAttr(::new (S.Context) ArgumentWithTypeTagAttr(
- S.Context, AL, AL.getArgAsIdent(0)->Ident, ArgumentIdx, TypeTagIdx,
- IsPointer));
- }
- static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!AL.isArgIdent(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type)
- << AL << 1 << AANT_ArgumentIdentifier;
- return;
- }
- if (!checkAttributeNumArgs(S, AL, 1))
- return;
- if (!isa<VarDecl>(D)) {
- S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type)
- << AL << ExpectedVariable;
- return;
- }
- IdentifierInfo *PointerKind = AL.getArgAsIdent(0)->Ident;
- TypeSourceInfo *MatchingCTypeLoc = nullptr;
- S.GetTypeFromParser(AL.getMatchingCType(), &MatchingCTypeLoc);
- assert(MatchingCTypeLoc && "no type source info for attribute argument");
- D->addAttr(::new (S.Context) TypeTagForDatatypeAttr(
- S.Context, AL, PointerKind, MatchingCTypeLoc, AL.getLayoutCompatible(),
- AL.getMustBeNull()));
- }
- static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- ParamIdx ArgCount;
- if (!checkFunctionOrMethodParameterIndex(S, D, AL, 1, AL.getArgAsExpr(0),
- ArgCount,
- true /* CanIndexImplicitThis */))
- return;
- // ArgCount isn't a parameter index [0;n), it's a count [1;n]
- D->addAttr(::new (S.Context)
- XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex()));
- }
- //===----------------------------------------------------------------------===//
- // Checker-specific attribute handlers.
- //===----------------------------------------------------------------------===//
- static bool isValidSubjectOfNSReturnsRetainedAttribute(QualType QT) {
- return QT->isDependentType() || QT->isObjCRetainableType();
- }
- static bool isValidSubjectOfNSAttribute(QualType QT) {
- return QT->isDependentType() || QT->isObjCObjectPointerType() ||
- QT->isObjCNSObjectType();
- }
- static bool isValidSubjectOfCFAttribute(QualType QT) {
- return QT->isDependentType() || QT->isPointerType() ||
- isValidSubjectOfNSAttribute(QT);
- }
- static bool isValidSubjectOfOSAttribute(QualType QT) {
- if (QT->isDependentType())
- return true;
- QualType PT = QT->getPointeeType();
- return !PT.isNull() && PT->getAsCXXRecordDecl() != nullptr;
- }
- void Sema::AddXConsumedAttr(Decl *D, const AttributeCommonInfo &CI,
- RetainOwnershipKind K,
- bool IsTemplateInstantiation) {
- ValueDecl *VD = cast<ValueDecl>(D);
- switch (K) {
- case RetainOwnershipKind::OS:
- handleSimpleAttributeOrDiagnose<OSConsumedAttr>(
- *this, VD, CI, isValidSubjectOfOSAttribute(VD->getType()),
- diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/CI.getRange(), "os_consumed", /*pointers*/ 1);
- return;
- case RetainOwnershipKind::NS:
- handleSimpleAttributeOrDiagnose<NSConsumedAttr>(
- *this, VD, CI, isValidSubjectOfNSAttribute(VD->getType()),
- // These attributes are normally just advisory, but in ARC, ns_consumed
- // is significant. Allow non-dependent code to contain inappropriate
- // attributes even in ARC, but require template instantiations to be
- // set up correctly.
- ((IsTemplateInstantiation && getLangOpts().ObjCAutoRefCount)
- ? diag::err_ns_attribute_wrong_parameter_type
- : diag::warn_ns_attribute_wrong_parameter_type),
- /*ExtraArgs=*/CI.getRange(), "ns_consumed", /*objc pointers*/ 0);
- return;
- case RetainOwnershipKind::CF:
- handleSimpleAttributeOrDiagnose<CFConsumedAttr>(
- *this, VD, CI, isValidSubjectOfCFAttribute(VD->getType()),
- diag::warn_ns_attribute_wrong_parameter_type,
- /*ExtraArgs=*/CI.getRange(), "cf_consumed", /*pointers*/ 1);
- return;
- }
- }
- static Sema::RetainOwnershipKind
- parsedAttrToRetainOwnershipKind(const ParsedAttr &AL) {
- switch (AL.getKind()) {
- case ParsedAttr::AT_CFConsumed:
- case ParsedAttr::AT_CFReturnsRetained:
- case ParsedAttr::AT_CFReturnsNotRetained:
- return Sema::RetainOwnershipKind::CF;
- case ParsedAttr::AT_OSConsumesThis:
- case ParsedAttr::AT_OSConsumed:
- case ParsedAttr::AT_OSReturnsRetained:
- case ParsedAttr::AT_OSReturnsNotRetained:
- case ParsedAttr::AT_OSReturnsRetainedOnZero:
- case ParsedAttr::AT_OSReturnsRetainedOnNonZero:
- return Sema::RetainOwnershipKind::OS;
- case ParsedAttr::AT_NSConsumesSelf:
- case ParsedAttr::AT_NSConsumed:
- case ParsedAttr::AT_NSReturnsRetained:
- case ParsedAttr::AT_NSReturnsNotRetained:
- case ParsedAttr::AT_NSReturnsAutoreleased:
- return Sema::RetainOwnershipKind::NS;
- default:
- llvm_unreachable("Wrong argument supplied");
- }
- }
- bool Sema::checkNSReturnsRetainedReturnType(SourceLocation Loc, QualType QT) {
- if (isValidSubjectOfNSReturnsRetainedAttribute(QT))
- return false;
- Diag(Loc, diag::warn_ns_attribute_wrong_return_type)
- << "'ns_returns_retained'" << 0 << 0;
- return true;
- }
- /// \return whether the parameter is a pointer to OSObject pointer.
- static bool isValidOSObjectOutParameter(const Decl *D) {
- const auto *PVD = dyn_cast<ParmVarDecl>(D);
- if (!PVD)
- return false;
- QualType QT = PVD->getType();
- QualType PT = QT->getPointeeType();
- return !PT.isNull() && isValidSubjectOfOSAttribute(PT);
- }
- static void handleXReturnsXRetainedAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- QualType ReturnType;
- Sema::RetainOwnershipKind K = parsedAttrToRetainOwnershipKind(AL);
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- ReturnType = MD->getReturnType();
- } else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) &&
- (AL.getKind() == ParsedAttr::AT_NSReturnsRetained)) {
- return; // ignore: was handled as a type attribute
- } else if (const auto *PD = dyn_cast<ObjCPropertyDecl>(D)) {
- ReturnType = PD->getType();
- } else if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- ReturnType = FD->getReturnType();
- } else if (const auto *Param = dyn_cast<ParmVarDecl>(D)) {
- // Attributes on parameters are used for out-parameters,
- // passed as pointers-to-pointers.
- unsigned DiagID = K == Sema::RetainOwnershipKind::CF
- ? /*pointer-to-CF-pointer*/2
- : /*pointer-to-OSObject-pointer*/3;
- ReturnType = Param->getType()->getPointeeType();
- if (ReturnType.isNull()) {
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type)
- << AL << DiagID << AL.getRange();
- return;
- }
- } else if (AL.isUsedAsTypeAttr()) {
- return;
- } else {
- AttributeDeclKind ExpectedDeclKind;
- switch (AL.getKind()) {
- default: llvm_unreachable("invalid ownership attribute");
- case ParsedAttr::AT_NSReturnsRetained:
- case ParsedAttr::AT_NSReturnsAutoreleased:
- case ParsedAttr::AT_NSReturnsNotRetained:
- ExpectedDeclKind = ExpectedFunctionOrMethod;
- break;
- case ParsedAttr::AT_OSReturnsRetained:
- case ParsedAttr::AT_OSReturnsNotRetained:
- case ParsedAttr::AT_CFReturnsRetained:
- case ParsedAttr::AT_CFReturnsNotRetained:
- ExpectedDeclKind = ExpectedFunctionMethodOrParameter;
- break;
- }
- S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type)
- << AL.getRange() << AL << ExpectedDeclKind;
- return;
- }
- bool TypeOK;
- bool Cf;
- unsigned ParmDiagID = 2; // Pointer-to-CF-pointer
- switch (AL.getKind()) {
- default: llvm_unreachable("invalid ownership attribute");
- case ParsedAttr::AT_NSReturnsRetained:
- TypeOK = isValidSubjectOfNSReturnsRetainedAttribute(ReturnType);
- Cf = false;
- break;
- case ParsedAttr::AT_NSReturnsAutoreleased:
- case ParsedAttr::AT_NSReturnsNotRetained:
- TypeOK = isValidSubjectOfNSAttribute(ReturnType);
- Cf = false;
- break;
- case ParsedAttr::AT_CFReturnsRetained:
- case ParsedAttr::AT_CFReturnsNotRetained:
- TypeOK = isValidSubjectOfCFAttribute(ReturnType);
- Cf = true;
- break;
- case ParsedAttr::AT_OSReturnsRetained:
- case ParsedAttr::AT_OSReturnsNotRetained:
- TypeOK = isValidSubjectOfOSAttribute(ReturnType);
- Cf = true;
- ParmDiagID = 3; // Pointer-to-OSObject-pointer
- break;
- }
- if (!TypeOK) {
- if (AL.isUsedAsTypeAttr())
- return;
- if (isa<ParmVarDecl>(D)) {
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_parameter_type)
- << AL << ParmDiagID << AL.getRange();
- } else {
- // Needs to be kept in sync with warn_ns_attribute_wrong_return_type.
- enum : unsigned {
- Function,
- Method,
- Property
- } SubjectKind = Function;
- if (isa<ObjCMethodDecl>(D))
- SubjectKind = Method;
- else if (isa<ObjCPropertyDecl>(D))
- SubjectKind = Property;
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type)
- << AL << SubjectKind << Cf << AL.getRange();
- }
- return;
- }
- switch (AL.getKind()) {
- default:
- llvm_unreachable("invalid ownership attribute");
- case ParsedAttr::AT_NSReturnsAutoreleased:
- handleSimpleAttribute<NSReturnsAutoreleasedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_CFReturnsNotRetained:
- handleSimpleAttribute<CFReturnsNotRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_NSReturnsNotRetained:
- handleSimpleAttribute<NSReturnsNotRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_CFReturnsRetained:
- handleSimpleAttribute<CFReturnsRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_NSReturnsRetained:
- handleSimpleAttribute<NSReturnsRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_OSReturnsRetained:
- handleSimpleAttribute<OSReturnsRetainedAttr>(S, D, AL);
- return;
- case ParsedAttr::AT_OSReturnsNotRetained:
- handleSimpleAttribute<OSReturnsNotRetainedAttr>(S, D, AL);
- return;
- };
- }
- static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D,
- const ParsedAttr &Attrs) {
- const int EP_ObjCMethod = 1;
- const int EP_ObjCProperty = 2;
- SourceLocation loc = Attrs.getLoc();
- QualType resultType;
- if (isa<ObjCMethodDecl>(D))
- resultType = cast<ObjCMethodDecl>(D)->getReturnType();
- else
- resultType = cast<ObjCPropertyDecl>(D)->getType();
- if (!resultType->isReferenceType() &&
- (!resultType->isPointerType() || resultType->isObjCRetainableType())) {
- S.Diag(D->getBeginLoc(), diag::warn_ns_attribute_wrong_return_type)
- << SourceRange(loc) << Attrs
- << (isa<ObjCMethodDecl>(D) ? EP_ObjCMethod : EP_ObjCProperty)
- << /*non-retainable pointer*/ 2;
- // Drop the attribute.
- return;
- }
- D->addAttr(::new (S.Context) ObjCReturnsInnerPointerAttr(S.Context, Attrs));
- }
- static void handleObjCRequiresSuperAttr(Sema &S, Decl *D,
- const ParsedAttr &Attrs) {
- const auto *Method = cast<ObjCMethodDecl>(D);
- const DeclContext *DC = Method->getDeclContext();
- if (const auto *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) {
- S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs
- << 0;
- S.Diag(PDecl->getLocation(), diag::note_protocol_decl);
- return;
- }
- if (Method->getMethodFamily() == OMF_dealloc) {
- S.Diag(D->getBeginLoc(), diag::warn_objc_requires_super_protocol) << Attrs
- << 1;
- return;
- }
- D->addAttr(::new (S.Context) ObjCRequiresSuperAttr(S.Context, Attrs));
- }
- static void handleObjCBridgeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
- if (!Parm) {
- S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
- return;
- }
- // Typedefs only allow objc_bridge(id) and have some additional checking.
- if (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (!Parm->Ident->isStr("id")) {
- S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_id) << AL;
- return;
- }
- // Only allow 'cv void *'.
- QualType T = TD->getUnderlyingType();
- if (!T->isVoidPointerType()) {
- S.Diag(AL.getLoc(), diag::err_objc_attr_typedef_not_void_pointer);
- return;
- }
- }
- D->addAttr(::new (S.Context) ObjCBridgeAttr(S.Context, AL, Parm->Ident));
- }
- static void handleObjCBridgeMutableAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- IdentifierLoc *Parm = AL.isArgIdent(0) ? AL.getArgAsIdent(0) : nullptr;
- if (!Parm) {
- S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
- return;
- }
- D->addAttr(::new (S.Context)
- ObjCBridgeMutableAttr(S.Context, AL, Parm->Ident));
- }
- static void handleObjCBridgeRelatedAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- IdentifierInfo *RelatedClass =
- AL.isArgIdent(0) ? AL.getArgAsIdent(0)->Ident : nullptr;
- if (!RelatedClass) {
- S.Diag(D->getBeginLoc(), diag::err_objc_attr_not_id) << AL << 0;
- return;
- }
- IdentifierInfo *ClassMethod =
- AL.getArgAsIdent(1) ? AL.getArgAsIdent(1)->Ident : nullptr;
- IdentifierInfo *InstanceMethod =
- AL.getArgAsIdent(2) ? AL.getArgAsIdent(2)->Ident : nullptr;
- D->addAttr(::new (S.Context) ObjCBridgeRelatedAttr(
- S.Context, AL, RelatedClass, ClassMethod, InstanceMethod));
- }
- static void handleObjCDesignatedInitializer(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- DeclContext *Ctx = D->getDeclContext();
- // This attribute can only be applied to methods in interfaces or class
- // extensions.
- if (!isa<ObjCInterfaceDecl>(Ctx) &&
- !(isa<ObjCCategoryDecl>(Ctx) &&
- cast<ObjCCategoryDecl>(Ctx)->IsClassExtension())) {
- S.Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
- return;
- }
- ObjCInterfaceDecl *IFace;
- if (auto *CatDecl = dyn_cast<ObjCCategoryDecl>(Ctx))
- IFace = CatDecl->getClassInterface();
- else
- IFace = cast<ObjCInterfaceDecl>(Ctx);
- if (!IFace)
- return;
- IFace->setHasDesignatedInitializers();
- D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(S.Context, AL));
- }
- static void handleObjCRuntimeName(Sema &S, Decl *D, const ParsedAttr &AL) {
- StringRef MetaDataName;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, MetaDataName))
- return;
- D->addAttr(::new (S.Context)
- ObjCRuntimeNameAttr(S.Context, AL, MetaDataName));
- }
- // When a user wants to use objc_boxable with a union or struct
- // but they don't have access to the declaration (legacy/third-party code)
- // then they can 'enable' this feature with a typedef:
- // typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct;
- static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) {
- bool notify = false;
- auto *RD = dyn_cast<RecordDecl>(D);
- if (RD && RD->getDefinition()) {
- RD = RD->getDefinition();
- notify = true;
- }
- if (RD) {
- ObjCBoxableAttr *BoxableAttr =
- ::new (S.Context) ObjCBoxableAttr(S.Context, AL);
- RD->addAttr(BoxableAttr);
- if (notify) {
- // we need to notify ASTReader/ASTWriter about
- // modification of existing declaration
- if (ASTMutationListener *L = S.getASTMutationListener())
- L->AddedAttributeToRecord(BoxableAttr, RD);
- }
- }
- }
- static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (hasDeclarator(D)) return;
- S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type)
- << AL.getRange() << AL << ExpectedVariable;
- }
- static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- const auto *VD = cast<ValueDecl>(D);
- QualType QT = VD->getType();
- if (!QT->isDependentType() &&
- !QT->isObjCLifetimeType()) {
- S.Diag(AL.getLoc(), diag::err_objc_precise_lifetime_bad_type)
- << QT;
- return;
- }
- Qualifiers::ObjCLifetime Lifetime = QT.getObjCLifetime();
- // If we have no lifetime yet, check the lifetime we're presumably
- // going to infer.
- if (Lifetime == Qualifiers::OCL_None && !QT->isDependentType())
- Lifetime = QT->getObjCARCImplicitLifetime();
- switch (Lifetime) {
- case Qualifiers::OCL_None:
- assert(QT->isDependentType() &&
- "didn't infer lifetime for non-dependent type?");
- break;
- case Qualifiers::OCL_Weak: // meaningful
- case Qualifiers::OCL_Strong: // meaningful
- break;
- case Qualifiers::OCL_ExplicitNone:
- case Qualifiers::OCL_Autoreleasing:
- S.Diag(AL.getLoc(), diag::warn_objc_precise_lifetime_meaningless)
- << (Lifetime == Qualifiers::OCL_Autoreleasing);
- break;
- }
- D->addAttr(::new (S.Context) ObjCPreciseLifetimeAttr(S.Context, AL));
- }
- //===----------------------------------------------------------------------===//
- // Microsoft specific attribute handlers.
- //===----------------------------------------------------------------------===//
- UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI,
- StringRef Uuid) {
- if (const auto *UA = D->getAttr<UuidAttr>()) {
- if (UA->getGuid().equals_lower(Uuid))
- return nullptr;
- Diag(UA->getLocation(), diag::err_mismatched_uuid);
- Diag(CI.getLoc(), diag::note_previous_uuid);
- D->dropAttr<UuidAttr>();
- }
- return ::new (Context) UuidAttr(Context, CI, Uuid);
- }
- static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!S.LangOpts.CPlusPlus) {
- S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
- << AL << AttributeLangSupport::C;
- return;
- }
- StringRef StrRef;
- SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc))
- return;
- // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or
- // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former.
- if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}')
- StrRef = StrRef.drop_front().drop_back();
- // Validate GUID length.
- if (StrRef.size() != 36) {
- S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
- return;
- }
- for (unsigned i = 0; i < 36; ++i) {
- if (i == 8 || i == 13 || i == 18 || i == 23) {
- if (StrRef[i] != '-') {
- S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
- return;
- }
- } else if (!isHexDigit(StrRef[i])) {
- S.Diag(LiteralLoc, diag::err_attribute_uuid_malformed_guid);
- return;
- }
- }
- // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's
- // the only thing in the [] list, the [] too), and add an insertion of
- // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas
- // separating attributes nor of the [ and the ] are in the AST.
- // Cf "SourceLocations of attribute list delimiters - [[ ... , ... ]] etc"
- // on cfe-dev.
- if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling.
- S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated);
- UuidAttr *UA = S.mergeUuidAttr(D, AL, StrRef);
- if (UA)
- D->addAttr(UA);
- }
- static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!S.LangOpts.CPlusPlus) {
- S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang)
- << AL << AttributeLangSupport::C;
- return;
- }
- MSInheritanceAttr *IA = S.mergeMSInheritanceAttr(
- D, AL, /*BestCase=*/true,
- (MSInheritanceAttr::Spelling)AL.getSemanticSpelling());
- if (IA) {
- D->addAttr(IA);
- S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
- }
- }
- static void handleDeclspecThreadAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- const auto *VD = cast<VarDecl>(D);
- if (!S.Context.getTargetInfo().isTLSSupported()) {
- S.Diag(AL.getLoc(), diag::err_thread_unsupported);
- return;
- }
- if (VD->getTSCSpec() != TSCS_unspecified) {
- S.Diag(AL.getLoc(), diag::err_declspec_thread_on_thread_variable);
- return;
- }
- if (VD->hasLocalStorage()) {
- S.Diag(AL.getLoc(), diag::err_thread_non_global) << "__declspec(thread)";
- return;
- }
- D->addAttr(::new (S.Context) ThreadAttr(S.Context, AL));
- }
- static void handleAbiTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- SmallVector<StringRef, 4> Tags;
- for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
- StringRef Tag;
- if (!S.checkStringLiteralArgumentAttr(AL, I, Tag))
- return;
- Tags.push_back(Tag);
- }
- if (const auto *NS = dyn_cast<NamespaceDecl>(D)) {
- if (!NS->isInline()) {
- S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 0;
- return;
- }
- if (NS->isAnonymousNamespace()) {
- S.Diag(AL.getLoc(), diag::warn_attr_abi_tag_namespace) << 1;
- return;
- }
- if (AL.getNumArgs() == 0)
- Tags.push_back(NS->getName());
- } else if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- // Store tags sorted and without duplicates.
- llvm::sort(Tags);
- Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
- D->addAttr(::new (S.Context)
- AbiTagAttr(S.Context, AL, Tags.data(), Tags.size()));
- }
- static void handleARMInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Check the attribute arguments.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
- return;
- }
- StringRef Str;
- SourceLocation ArgLoc;
- if (AL.getNumArgs() == 0)
- Str = "";
- else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
- ARMInterruptAttr::InterruptType Kind;
- if (!ARMInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str
- << ArgLoc;
- return;
- }
- D->addAttr(::new (S.Context) ARMInterruptAttr(S.Context, AL, Kind));
- }
- static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // MSP430 'interrupt' attribute is applied to
- // a function with no parameters and void return type.
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'interrupt'" << ExpectedFunctionOrMethod;
- return;
- }
- if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MSP430*/ 1 << 0;
- return;
- }
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MSP430*/ 1 << 1;
- return;
- }
- // The attribute takes one integer argument.
- if (!checkAttributeNumArgs(S, AL, 1))
- return;
- if (!AL.isArgExpr(0)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIntegerConstant;
- return;
- }
- Expr *NumParamsExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
- llvm::APSInt NumParams(32);
- if (!NumParamsExpr->isIntegerConstantExpr(NumParams, S.Context)) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_type)
- << AL << AANT_ArgumentIntegerConstant
- << NumParamsExpr->getSourceRange();
- return;
- }
- // The argument should be in range 0..63.
- unsigned Num = NumParams.getLimitedValue(255);
- if (Num > 63) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << (int)NumParams.getSExtValue()
- << NumParamsExpr->getSourceRange();
- return;
- }
- D->addAttr(::new (S.Context) MSP430InterruptAttr(S.Context, AL, Num));
- D->addAttr(UsedAttr::CreateImplicit(S.Context));
- }
- static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Only one optional argument permitted.
- if (AL.getNumArgs() > 1) {
- S.Diag(AL.getLoc(), diag::err_attribute_too_many_arguments) << AL << 1;
- return;
- }
- StringRef Str;
- SourceLocation ArgLoc;
- if (AL.getNumArgs() == 0)
- Str = "";
- else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
- // Semantic checks for a function with the 'interrupt' attribute for MIPS:
- // a) Must be a function.
- // b) Must have no parameters.
- // c) Must have the 'void' return type.
- // d) Cannot have the 'mips16' attribute, as that instruction set
- // lacks the 'eret' instruction.
- // e) The attribute itself must either have no argument or one of the
- // valid interrupt types, see [MipsInterruptDocs].
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'interrupt'" << ExpectedFunctionOrMethod;
- return;
- }
- if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MIPS*/ 0 << 0;
- return;
- }
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*MIPS*/ 0 << 1;
- return;
- }
- if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL))
- return;
- MipsInterruptAttr::InterruptType Kind;
- if (!MipsInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported)
- << AL << "'" + std::string(Str) + "'";
- return;
- }
- D->addAttr(::new (S.Context) MipsInterruptAttr(S.Context, AL, Kind));
- }
- static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Semantic checks for a function with the 'interrupt' attribute.
- // a) Must be a function.
- // b) Must have the 'void' return type.
- // c) Must take 1 or 2 arguments.
- // d) The 1st argument must be a pointer.
- // e) The 2nd argument (if any) must be an unsigned integer.
- if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) ||
- CXXMethodDecl::isStaticOverloadedOperator(
- cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << ExpectedFunctionWithProtoType;
- return;
- }
- // Interrupt handler must have void return type.
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
- diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 0;
- return;
- }
- // Interrupt handler must have 1 or 2 parameters.
- unsigned NumParams = getFunctionOrMethodNumParams(D);
- if (NumParams < 1 || NumParams > 2) {
- S.Diag(D->getBeginLoc(), diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 1;
- return;
- }
- // The first argument must be a pointer.
- if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
- S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
- diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 2;
- return;
- }
- // The second argument, if present, must be an unsigned integer.
- unsigned TypeSize =
- S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
- ? 64
- : 32;
- if (NumParams == 2 &&
- (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
- S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
- S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
- diag::err_anyx86_interrupt_attribute)
- << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
- ? 0
- : 1)
- << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
- return;
- }
- D->addAttr(::new (S.Context) AnyX86InterruptAttr(S.Context, AL));
- D->addAttr(UsedAttr::CreateImplicit(S.Context));
- }
- static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'interrupt'" << ExpectedFunction;
- return;
- }
- if (!checkAttributeNumArgs(S, AL, 0))
- return;
- handleSimpleAttribute<AVRInterruptAttr>(S, D, AL);
- }
- static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'signal'" << ExpectedFunction;
- return;
- }
- if (!checkAttributeNumArgs(S, AL, 0))
- return;
- handleSimpleAttribute<AVRSignalAttr>(S, D, AL);
- }
- static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'import_module'" << ExpectedFunction;
- return;
- }
- auto *FD = cast<FunctionDecl>(D);
- if (FD->isThisDeclarationADefinition()) {
- S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
- return;
- }
- StringRef Str;
- SourceLocation ArgLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
- FD->addAttr(::new (S.Context)
- WebAssemblyImportModuleAttr(S.Context, AL, Str));
- }
- static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!isFunctionOrMethod(D)) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'import_name'" << ExpectedFunction;
- return;
- }
- auto *FD = cast<FunctionDecl>(D);
- if (FD->isThisDeclarationADefinition()) {
- S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0;
- return;
- }
- StringRef Str;
- SourceLocation ArgLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
- FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str));
- }
- static void handleRISCVInterruptAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- // Warn about repeated attributes.
- if (const auto *A = D->getAttr<RISCVInterruptAttr>()) {
- S.Diag(AL.getRange().getBegin(),
- diag::warn_riscv_repeated_interrupt_attribute);
- S.Diag(A->getLocation(), diag::note_riscv_repeated_interrupt_attribute);
- return;
- }
- // Check the attribute argument. Argument is optional.
- if (!checkAttributeAtMostNumArgs(S, AL, 1))
- return;
- StringRef Str;
- SourceLocation ArgLoc;
- // 'machine'is the default interrupt mode.
- if (AL.getNumArgs() == 0)
- Str = "machine";
- else if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc))
- return;
- // Semantic checks for a function with the 'interrupt' attribute:
- // - Must be a function.
- // - Must have no parameters.
- // - Must have the 'void' return type.
- // - The attribute itself must either have no argument or one of the
- // valid interrupt types, see [RISCVInterruptDocs].
- if (D->getFunctionType() == nullptr) {
- S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type)
- << "'interrupt'" << ExpectedFunction;
- return;
- }
- if (hasFunctionProto(D) && getFunctionOrMethodNumParams(D) != 0) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*RISC-V*/ 2 << 0;
- return;
- }
- if (!getFunctionOrMethodResultType(D)->isVoidType()) {
- S.Diag(D->getLocation(), diag::warn_interrupt_attribute_invalid)
- << /*RISC-V*/ 2 << 1;
- return;
- }
- RISCVInterruptAttr::InterruptType Kind;
- if (!RISCVInterruptAttr::ConvertStrToInterruptType(Str, Kind)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << Str
- << ArgLoc;
- return;
- }
- D->addAttr(::new (S.Context) RISCVInterruptAttr(S.Context, AL, Kind));
- }
- static void handleInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Dispatch the interrupt attribute based on the current target.
- switch (S.Context.getTargetInfo().getTriple().getArch()) {
- case llvm::Triple::msp430:
- handleMSP430InterruptAttr(S, D, AL);
- break;
- case llvm::Triple::mipsel:
- case llvm::Triple::mips:
- handleMipsInterruptAttr(S, D, AL);
- break;
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- handleAnyX86InterruptAttr(S, D, AL);
- break;
- case llvm::Triple::avr:
- handleAVRInterruptAttr(S, D, AL);
- break;
- case llvm::Triple::riscv32:
- case llvm::Triple::riscv64:
- handleRISCVInterruptAttr(S, D, AL);
- break;
- default:
- handleARMInterruptAttr(S, D, AL);
- break;
- }
- }
- static bool
- checkAMDGPUFlatWorkGroupSizeArguments(Sema &S, Expr *MinExpr, Expr *MaxExpr,
- const AMDGPUFlatWorkGroupSizeAttr &Attr) {
- // Accept template arguments for now as they depend on something else.
- // We'll get to check them when they eventually get instantiated.
- if (MinExpr->isValueDependent() || MaxExpr->isValueDependent())
- return false;
- uint32_t Min = 0;
- if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
- return true;
- uint32_t Max = 0;
- if (!checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
- return true;
- if (Min == 0 && Max != 0) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 0;
- return true;
- }
- if (Min > Max) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 1;
- return true;
- }
- return false;
- }
- void Sema::addAMDGPUFlatWorkGroupSizeAttr(Decl *D,
- const AttributeCommonInfo &CI,
- Expr *MinExpr, Expr *MaxExpr) {
- AMDGPUFlatWorkGroupSizeAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
- if (checkAMDGPUFlatWorkGroupSizeArguments(*this, MinExpr, MaxExpr, TmpAttr))
- return;
- D->addAttr(::new (Context)
- AMDGPUFlatWorkGroupSizeAttr(Context, CI, MinExpr, MaxExpr));
- }
- static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- Expr *MinExpr = AL.getArgAsExpr(0);
- Expr *MaxExpr = AL.getArgAsExpr(1);
- S.addAMDGPUFlatWorkGroupSizeAttr(D, AL, MinExpr, MaxExpr);
- }
- static bool checkAMDGPUWavesPerEUArguments(Sema &S, Expr *MinExpr,
- Expr *MaxExpr,
- const AMDGPUWavesPerEUAttr &Attr) {
- if (S.DiagnoseUnexpandedParameterPack(MinExpr) ||
- (MaxExpr && S.DiagnoseUnexpandedParameterPack(MaxExpr)))
- return true;
- // Accept template arguments for now as they depend on something else.
- // We'll get to check them when they eventually get instantiated.
- if (MinExpr->isValueDependent() || (MaxExpr && MaxExpr->isValueDependent()))
- return false;
- uint32_t Min = 0;
- if (!checkUInt32Argument(S, Attr, MinExpr, Min, 0))
- return true;
- uint32_t Max = 0;
- if (MaxExpr && !checkUInt32Argument(S, Attr, MaxExpr, Max, 1))
- return true;
- if (Min == 0 && Max != 0) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 0;
- return true;
- }
- if (Max != 0 && Min > Max) {
- S.Diag(Attr.getLocation(), diag::err_attribute_argument_invalid)
- << &Attr << 1;
- return true;
- }
- return false;
- }
- void Sema::addAMDGPUWavesPerEUAttr(Decl *D, const AttributeCommonInfo &CI,
- Expr *MinExpr, Expr *MaxExpr) {
- AMDGPUWavesPerEUAttr TmpAttr(Context, CI, MinExpr, MaxExpr);
- if (checkAMDGPUWavesPerEUArguments(*this, MinExpr, MaxExpr, TmpAttr))
- return;
- D->addAttr(::new (Context)
- AMDGPUWavesPerEUAttr(Context, CI, MinExpr, MaxExpr));
- }
- static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1) ||
- !checkAttributeAtMostNumArgs(S, AL, 2))
- return;
- Expr *MinExpr = AL.getArgAsExpr(0);
- Expr *MaxExpr = (AL.getNumArgs() > 1) ? AL.getArgAsExpr(1) : nullptr;
- S.addAMDGPUWavesPerEUAttr(D, AL, MinExpr, MaxExpr);
- }
- static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t NumSGPR = 0;
- Expr *NumSGPRExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, NumSGPRExpr, NumSGPR))
- return;
- D->addAttr(::new (S.Context) AMDGPUNumSGPRAttr(S.Context, AL, NumSGPR));
- }
- static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t NumVGPR = 0;
- Expr *NumVGPRExpr = AL.getArgAsExpr(0);
- if (!checkUInt32Argument(S, AL, NumVGPRExpr, NumVGPR))
- return;
- D->addAttr(::new (S.Context) AMDGPUNumVGPRAttr(S.Context, AL, NumVGPR));
- }
- static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- // If we try to apply it to a function pointer, don't warn, but don't
- // do anything, either. It doesn't matter anyway, because there's nothing
- // special about calling a force_align_arg_pointer function.
- const auto *VD = dyn_cast<ValueDecl>(D);
- if (VD && VD->getType()->isFunctionPointerType())
- return;
- // Also don't warn on function pointer typedefs.
- const auto *TD = dyn_cast<TypedefNameDecl>(D);
- if (TD && (TD->getUnderlyingType()->isFunctionPointerType() ||
- TD->getUnderlyingType()->isFunctionType()))
- return;
- // Attribute can only be applied to function types.
- if (!isa<FunctionDecl>(D)) {
- S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type)
- << AL << ExpectedFunction;
- return;
- }
- D->addAttr(::new (S.Context) X86ForceAlignArgPointerAttr(S.Context, AL));
- }
- static void handleLayoutVersion(Sema &S, Decl *D, const ParsedAttr &AL) {
- uint32_t Version;
- Expr *VersionExpr = static_cast<Expr *>(AL.getArgAsExpr(0));
- if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Version))
- return;
- // TODO: Investigate what happens with the next major version of MSVC.
- if (Version != LangOptions::MSVC2015 / 100) {
- S.Diag(AL.getLoc(), diag::err_attribute_argument_out_of_bounds)
- << AL << Version << VersionExpr->getSourceRange();
- return;
- }
- // The attribute expects a "major" version number like 19, but new versions of
- // MSVC have moved to updating the "minor", or less significant numbers, so we
- // have to multiply by 100 now.
- Version *= 100;
- D->addAttr(::new (S.Context) LayoutVersionAttr(S.Context, AL, Version));
- }
- DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D,
- const AttributeCommonInfo &CI) {
- if (D->hasAttr<DLLExportAttr>()) {
- Diag(CI.getLoc(), diag::warn_attribute_ignored) << "'dllimport'";
- return nullptr;
- }
- if (D->hasAttr<DLLImportAttr>())
- return nullptr;
- return ::new (Context) DLLImportAttr(Context, CI);
- }
- DLLExportAttr *Sema::mergeDLLExportAttr(Decl *D,
- const AttributeCommonInfo &CI) {
- if (DLLImportAttr *Import = D->getAttr<DLLImportAttr>()) {
- Diag(Import->getLocation(), diag::warn_attribute_ignored) << Import;
- D->dropAttr<DLLImportAttr>();
- }
- if (D->hasAttr<DLLExportAttr>())
- return nullptr;
- return ::new (Context) DLLExportAttr(Context, CI);
- }
- static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) {
- if (isa<ClassTemplatePartialSpecializationDecl>(D) &&
- S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored) << A;
- return;
- }
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- if (FD->isInlined() && A.getKind() == ParsedAttr::AT_DLLImport &&
- !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
- // MinGW doesn't allow dllimport on inline functions.
- S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline)
- << A;
- return;
- }
- }
- if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (S.Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- MD->getParent()->isLambda()) {
- S.Diag(A.getRange().getBegin(), diag::err_attribute_dll_lambda) << A;
- return;
- }
- }
- Attr *NewAttr = A.getKind() == ParsedAttr::AT_DLLExport
- ? (Attr *)S.mergeDLLExportAttr(D, A)
- : (Attr *)S.mergeDLLImportAttr(D, A);
- if (NewAttr)
- D->addAttr(NewAttr);
- }
- MSInheritanceAttr *
- Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI,
- bool BestCase,
- MSInheritanceAttr::Spelling SemanticSpelling) {
- if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) {
- if (IA->getSemanticSpelling() == SemanticSpelling)
- return nullptr;
- Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance)
- << 1 /*previous declaration*/;
- Diag(CI.getLoc(), diag::note_previous_ms_inheritance);
- D->dropAttr<MSInheritanceAttr>();
- }
- auto *RD = cast<CXXRecordDecl>(D);
- if (RD->hasDefinition()) {
- if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase,
- SemanticSpelling)) {
- return nullptr;
- }
- } else {
- if (isa<ClassTemplatePartialSpecializationDecl>(RD)) {
- Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
- << 1 /*partial specialization*/;
- return nullptr;
- }
- if (RD->getDescribedClassTemplate()) {
- Diag(CI.getLoc(), diag::warn_ignored_ms_inheritance)
- << 0 /*primary template*/;
- return nullptr;
- }
- }
- return ::new (Context) MSInheritanceAttr(Context, CI, BestCase);
- }
- static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // The capability attributes take a single string parameter for the name of
- // the capability they represent. The lockable attribute does not take any
- // parameters. However, semantically, both attributes represent the same
- // concept, and so they use the same semantic attribute. Eventually, the
- // lockable attribute will be removed.
- //
- // For backward compatibility, any capability which has no specified string
- // literal will be considered a "mutex."
- StringRef N("mutex");
- SourceLocation LiteralLoc;
- if (AL.getKind() == ParsedAttr::AT_Capability &&
- !S.checkStringLiteralArgumentAttr(AL, 0, N, &LiteralLoc))
- return;
- // Currently, there are only two names allowed for a capability: role and
- // mutex (case insensitive). Diagnose other capability names.
- if (!N.equals_lower("mutex") && !N.equals_lower("role"))
- S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N;
- D->addAttr(::new (S.Context) CapabilityAttr(S.Context, AL, N));
- }
- static void handleAssertCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- SmallVector<Expr*, 1> Args;
- if (!checkLockFunAttrCommon(S, D, AL, Args))
- return;
- D->addAttr(::new (S.Context)
- AssertCapabilityAttr(S.Context, AL, Args.data(), Args.size()));
- }
- static void handleAcquireCapabilityAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- SmallVector<Expr*, 1> Args;
- if (!checkLockFunAttrCommon(S, D, AL, Args))
- return;
- D->addAttr(::new (S.Context) AcquireCapabilityAttr(S.Context, AL, Args.data(),
- Args.size()));
- }
- static void handleTryAcquireCapabilityAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- SmallVector<Expr*, 2> Args;
- if (!checkTryLockFunAttrCommon(S, D, AL, Args))
- return;
- D->addAttr(::new (S.Context) TryAcquireCapabilityAttr(
- S.Context, AL, AL.getArgAsExpr(0), Args.data(), Args.size()));
- }
- static void handleReleaseCapabilityAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- // Check that all arguments are lockable objects.
- SmallVector<Expr *, 1> Args;
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args, 0, true);
- D->addAttr(::new (S.Context) ReleaseCapabilityAttr(S.Context, AL, Args.data(),
- Args.size()));
- }
- static void handleRequiresCapabilityAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- // check that all arguments are lockable objects
- SmallVector<Expr*, 1> Args;
- checkAttrArgsAreCapabilityObjs(S, D, AL, Args);
- if (Args.empty())
- return;
- RequiresCapabilityAttr *RCA = ::new (S.Context)
- RequiresCapabilityAttr(S.Context, AL, Args.data(), Args.size());
- D->addAttr(RCA);
- }
- static void handleDeprecatedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (const auto *NSD = dyn_cast<NamespaceDecl>(D)) {
- if (NSD->isAnonymousNamespace()) {
- S.Diag(AL.getLoc(), diag::warn_deprecated_anonymous_namespace);
- // Do not want to attach the attribute to the namespace because that will
- // cause confusing diagnostic reports for uses of declarations within the
- // namespace.
- return;
- }
- }
- // Handle the cases where the attribute has a text message.
- StringRef Str, Replacement;
- if (AL.isArgExpr(0) && AL.getArgAsExpr(0) &&
- !S.checkStringLiteralArgumentAttr(AL, 0, Str))
- return;
- // Only support a single optional message for Declspec and CXX11.
- if (AL.isDeclspecAttribute() || AL.isCXX11Attribute())
- checkAttributeAtMostNumArgs(S, AL, 1);
- else if (AL.isArgExpr(1) && AL.getArgAsExpr(1) &&
- !S.checkStringLiteralArgumentAttr(AL, 1, Replacement))
- return;
- if (!S.getLangOpts().CPlusPlus14 && AL.isCXX11Attribute() && !AL.isGNUScope())
- S.Diag(AL.getLoc(), diag::ext_cxx14_attr) << AL;
- D->addAttr(::new (S.Context) DeprecatedAttr(S.Context, AL, Str, Replacement));
- }
- static bool isGlobalVar(const Decl *D) {
- if (const auto *S = dyn_cast<VarDecl>(D))
- return S->hasGlobalStorage();
- return false;
- }
- static void handleNoSanitizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (!checkAttributeAtLeastNumArgs(S, AL, 1))
- return;
- std::vector<StringRef> Sanitizers;
- for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
- StringRef SanitizerName;
- SourceLocation LiteralLoc;
- if (!S.checkStringLiteralArgumentAttr(AL, I, SanitizerName, &LiteralLoc))
- return;
- if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) ==
- SanitizerMask())
- S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName;
- else if (isGlobalVar(D) && SanitizerName != "address")
- S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << AL << ExpectedFunctionOrMethod;
- Sanitizers.push_back(SanitizerName);
- }
- D->addAttr(::new (S.Context) NoSanitizeAttr(S.Context, AL, Sanitizers.data(),
- Sanitizers.size()));
- }
- static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- StringRef AttrName = AL.getAttrName()->getName();
- normalizeName(AttrName);
- StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName)
- .Case("no_address_safety_analysis", "address")
- .Case("no_sanitize_address", "address")
- .Case("no_sanitize_thread", "thread")
- .Case("no_sanitize_memory", "memory");
- if (isGlobalVar(D) && SanitizerName != "address")
- S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << AL << ExpectedFunction;
- // FIXME: Rather than create a NoSanitizeSpecificAttr, this creates a
- // NoSanitizeAttr object; but we need to calculate the correct spelling list
- // index rather than incorrectly assume the index for NoSanitizeSpecificAttr
- // has the same spellings as the index for NoSanitizeAttr. We don't have a
- // general way to "translate" between the two, so this hack attempts to work
- // around the issue with hard-coded indicies. This is critical for calling
- // getSpelling() or prettyPrint() on the resulting semantic attribute object
- // without failing assertions.
- unsigned TranslatedSpellingIndex = 0;
- if (AL.isC2xAttribute() || AL.isCXX11Attribute())
- TranslatedSpellingIndex = 1;
- AttributeCommonInfo Info = AL;
- Info.setAttributeSpellingListIndex(TranslatedSpellingIndex);
- D->addAttr(::new (S.Context)
- NoSanitizeAttr(S.Context, Info, &SanitizerName, 1));
- }
- static void handleInternalLinkageAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (InternalLinkageAttr *Internal = S.mergeInternalLinkageAttr(D, AL))
- D->addAttr(Internal);
- }
- static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (S.LangOpts.OpenCLVersion != 200)
- S.Diag(AL.getLoc(), diag::err_attribute_requires_opencl_version)
- << AL << "2.0" << 0;
- else
- S.Diag(AL.getLoc(), diag::warn_opencl_attr_deprecated_ignored) << AL
- << "2.0";
- }
- /// Handles semantic checking for features that are common to all attributes,
- /// such as checking whether a parameter was properly specified, or the correct
- /// number of arguments were passed, etc.
- static bool handleCommonAttributeFeatures(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- // Several attributes carry different semantics than the parsing requires, so
- // those are opted out of the common argument checks.
- //
- // We also bail on unknown and ignored attributes because those are handled
- // as part of the target-specific handling logic.
- if (AL.getKind() == ParsedAttr::UnknownAttribute)
- return false;
- // Check whether the attribute requires specific language extensions to be
- // enabled.
- if (!AL.diagnoseLangOpts(S))
- return true;
- // Check whether the attribute appertains to the given subject.
- if (!AL.diagnoseAppertainsTo(S, D))
- return true;
- if (AL.hasCustomParsing())
- return false;
- if (AL.getMinArgs() == AL.getMaxArgs()) {
- // If there are no optional arguments, then checking for the argument count
- // is trivial.
- if (!checkAttributeNumArgs(S, AL, AL.getMinArgs()))
- return true;
- } else {
- // There are optional arguments, so checking is slightly more involved.
- if (AL.getMinArgs() &&
- !checkAttributeAtLeastNumArgs(S, AL, AL.getMinArgs()))
- return true;
- else if (!AL.hasVariadicArg() && AL.getMaxArgs() &&
- !checkAttributeAtMostNumArgs(S, AL, AL.getMaxArgs()))
- return true;
- }
- if (S.CheckAttrTarget(AL))
- return true;
- return false;
- }
- static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- if (D->isInvalidDecl())
- return;
- // Check if there is only one access qualifier.
- if (D->hasAttr<OpenCLAccessAttr>()) {
- if (D->getAttr<OpenCLAccessAttr>()->getSemanticSpelling() ==
- AL.getSemanticSpelling()) {
- S.Diag(AL.getLoc(), diag::warn_duplicate_declspec)
- << AL.getAttrName()->getName() << AL.getRange();
- } else {
- S.Diag(AL.getLoc(), diag::err_opencl_multiple_access_qualifiers)
- << D->getSourceRange();
- D->setInvalidDecl(true);
- return;
- }
- }
- // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that an
- // image object can be read and written.
- // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe
- // object. Using the read_write (or __read_write) qualifier with the pipe
- // qualifier is a compilation error.
- if (const auto *PDecl = dyn_cast<ParmVarDecl>(D)) {
- const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
- if (AL.getAttrName()->getName().find("read_write") != StringRef::npos) {
- if ((!S.getLangOpts().OpenCLCPlusPlus &&
- S.getLangOpts().OpenCLVersion < 200) ||
- DeclTy->isPipeType()) {
- S.Diag(AL.getLoc(), diag::err_opencl_invalid_read_write)
- << AL << PDecl->getType() << DeclTy->isImageType();
- D->setInvalidDecl(true);
- return;
- }
- }
- }
- D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL));
- }
- static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
- if (!cast<VarDecl>(D)->hasGlobalStorage()) {
- S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var)
- << (A.getKind() == ParsedAttr::AT_AlwaysDestroy);
- return;
- }
- if (A.getKind() == ParsedAttr::AT_AlwaysDestroy)
- handleSimpleAttributeWithExclusions<AlwaysDestroyAttr, NoDestroyAttr>(S, D, A);
- else
- handleSimpleAttributeWithExclusions<NoDestroyAttr, AlwaysDestroyAttr>(S, D, A);
- }
- static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- assert(cast<VarDecl>(D)->getStorageDuration() == SD_Automatic &&
- "uninitialized is only valid on automatic duration variables");
- D->addAttr(::new (S.Context) UninitializedAttr(S.Context, AL));
- }
- static bool tryMakeVariablePseudoStrong(Sema &S, VarDecl *VD,
- bool DiagnoseFailure) {
- QualType Ty = VD->getType();
- if (!Ty->isObjCRetainableType()) {
- if (DiagnoseFailure) {
- S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
- << 0;
- }
- return false;
- }
- Qualifiers::ObjCLifetime LifetimeQual = Ty.getQualifiers().getObjCLifetime();
- // Sema::inferObjCARCLifetime must run after processing decl attributes
- // (because __block lowers to an attribute), so if the lifetime hasn't been
- // explicitly specified, infer it locally now.
- if (LifetimeQual == Qualifiers::OCL_None)
- LifetimeQual = Ty->getObjCARCImplicitLifetime();
- // The attributes only really makes sense for __strong variables; ignore any
- // attempts to annotate a parameter with any other lifetime qualifier.
- if (LifetimeQual != Qualifiers::OCL_Strong) {
- if (DiagnoseFailure) {
- S.Diag(VD->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
- << 1;
- }
- return false;
- }
- // Tampering with the type of a VarDecl here is a bit of a hack, but we need
- // to ensure that the variable is 'const' so that we can error on
- // modification, which can otherwise over-release.
- VD->setType(Ty.withConst());
- VD->setARCPseudoStrong(true);
- return true;
- }
- static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D,
- const ParsedAttr &AL) {
- if (auto *VD = dyn_cast<VarDecl>(D)) {
- assert(!isa<ParmVarDecl>(VD) && "should be diagnosed automatically");
- if (!VD->hasLocalStorage()) {
- S.Diag(D->getBeginLoc(), diag::warn_ignored_objc_externally_retained)
- << 0;
- return;
- }
- if (!tryMakeVariablePseudoStrong(S, VD, /*DiagnoseFailure=*/true))
- return;
- handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
- return;
- }
- // If D is a function-like declaration (method, block, or function), then we
- // make every parameter psuedo-strong.
- for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) {
- auto *PVD = const_cast<ParmVarDecl *>(getFunctionOrMethodParam(D, I));
- QualType Ty = PVD->getType();
- // If a user wrote a parameter with __strong explicitly, then assume they
- // want "real" strong semantics for that parameter. This works because if
- // the parameter was written with __strong, then the strong qualifier will
- // be non-local.
- if (Ty.getLocalUnqualifiedType().getQualifiers().getObjCLifetime() ==
- Qualifiers::OCL_Strong)
- continue;
- tryMakeVariablePseudoStrong(S, PVD, /*DiagnoseFailure=*/false);
- }
- handleSimpleAttribute<ObjCExternallyRetainedAttr>(S, D, AL);
- }
- static void handleMIGServerRoutineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Check that the return type is a `typedef int kern_return_t` or a typedef
- // around it, because otherwise MIG convention checks make no sense.
- // BlockDecl doesn't store a return type, so it's annoying to check,
- // so let's skip it for now.
- if (!isa<BlockDecl>(D)) {
- QualType T = getFunctionOrMethodResultType(D);
- bool IsKernReturnT = false;
- while (const auto *TT = T->getAs<TypedefType>()) {
- IsKernReturnT = (TT->getDecl()->getName() == "kern_return_t");
- T = TT->desugar();
- }
- if (!IsKernReturnT || T.getCanonicalType() != S.getASTContext().IntTy) {
- S.Diag(D->getBeginLoc(),
- diag::warn_mig_server_routine_does_not_return_kern_return_t);
- return;
- }
- }
- handleSimpleAttribute<MIGServerRoutineAttr>(S, D, AL);
- }
- static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
- // Warn if the return type is not a pointer or reference type.
- if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- QualType RetTy = FD->getReturnType();
- if (!RetTy->isPointerType() && !RetTy->isReferenceType()) {
- S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer)
- << AL.getRange() << RetTy;
- return;
- }
- }
- handleSimpleAttribute<MSAllocatorAttr>(S, D, AL);
- }
- //===----------------------------------------------------------------------===//
- // Top Level Sema Entry Points
- //===----------------------------------------------------------------------===//
- /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if
- /// the attribute applies to decls. If the attribute is a type attribute, just
- /// silently ignore it if a GNU attribute.
- static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
- const ParsedAttr &AL,
- bool IncludeCXX11Attributes) {
- if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
- return;
- // Ignore C++11 attributes on declarator chunks: they appertain to the type
- // instead.
- if (AL.isCXX11Attribute() && !IncludeCXX11Attributes)
- return;
- // Unknown attributes are automatically warned on. Target-specific attributes
- // which do not apply to the current target architecture are treated as
- // though they were unknown attributes.
- if (AL.getKind() == ParsedAttr::UnknownAttribute ||
- !AL.existsInTarget(S.Context.getTargetInfo())) {
- S.Diag(AL.getLoc(),
- AL.isDeclspecAttribute()
- ? (unsigned)diag::warn_unhandled_ms_attribute_ignored
- : (unsigned)diag::warn_unknown_attribute_ignored)
- << AL;
- return;
- }
- if (handleCommonAttributeFeatures(S, D, AL))
- return;
- switch (AL.getKind()) {
- default:
- if (!AL.isStmtAttr()) {
- // Type attributes are handled elsewhere; silently move on.
- assert(AL.isTypeAttr() && "Non-type attribute not handled");
- break;
- }
- S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)
- << AL << D->getLocation();
- break;
- case ParsedAttr::AT_Interrupt:
- handleInterruptAttr(S, D, AL);
- break;
- case ParsedAttr::AT_X86ForceAlignArgPointer:
- handleX86ForceAlignArgPointerAttr(S, D, AL);
- break;
- case ParsedAttr::AT_DLLExport:
- case ParsedAttr::AT_DLLImport:
- handleDLLAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Mips16:
- handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr,
- MipsInterruptAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoMips16:
- handleSimpleAttribute<NoMips16Attr>(S, D, AL);
- break;
- case ParsedAttr::AT_MicroMips:
- handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoMicroMips:
- handleSimpleAttribute<NoMicroMipsAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_MipsLongCall:
- handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>(
- S, D, AL);
- break;
- case ParsedAttr::AT_MipsShortCall:
- handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>(
- S, D, AL);
- break;
- case ParsedAttr::AT_AMDGPUFlatWorkGroupSize:
- handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AMDGPUWavesPerEU:
- handleAMDGPUWavesPerEUAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AMDGPUNumSGPR:
- handleAMDGPUNumSGPRAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AMDGPUNumVGPR:
- handleAMDGPUNumVGPRAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AVRSignal:
- handleAVRSignalAttr(S, D, AL);
- break;
- case ParsedAttr::AT_WebAssemblyImportModule:
- handleWebAssemblyImportModuleAttr(S, D, AL);
- break;
- case ParsedAttr::AT_WebAssemblyImportName:
- handleWebAssemblyImportNameAttr(S, D, AL);
- break;
- case ParsedAttr::AT_IBAction:
- handleSimpleAttribute<IBActionAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_IBOutlet:
- handleIBOutlet(S, D, AL);
- break;
- case ParsedAttr::AT_IBOutletCollection:
- handleIBOutletCollection(S, D, AL);
- break;
- case ParsedAttr::AT_IFunc:
- handleIFuncAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Alias:
- handleAliasAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Aligned:
- handleAlignedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AlignValue:
- handleAlignValueAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AllocSize:
- handleAllocSizeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AlwaysInline:
- handleAlwaysInlineAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Artificial:
- handleSimpleAttribute<ArtificialAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_AnalyzerNoReturn:
- handleAnalyzerNoReturnAttr(S, D, AL);
- break;
- case ParsedAttr::AT_TLSModel:
- handleTLSModelAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Annotate:
- handleAnnotateAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Availability:
- handleAvailabilityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_CarriesDependency:
- handleDependencyAttr(S, scope, D, AL);
- break;
- case ParsedAttr::AT_CPUDispatch:
- case ParsedAttr::AT_CPUSpecific:
- handleCPUSpecificAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Common:
- handleCommonAttr(S, D, AL);
- break;
- case ParsedAttr::AT_CUDAConstant:
- handleConstantAttr(S, D, AL);
- break;
- case ParsedAttr::AT_PassObjectSize:
- handlePassObjectSizeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Constructor:
- handleConstructorAttr(S, D, AL);
- break;
- case ParsedAttr::AT_CXX11NoReturn:
- handleSimpleAttribute<CXX11NoReturnAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Deprecated:
- handleDeprecatedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Destructor:
- handleDestructorAttr(S, D, AL);
- break;
- case ParsedAttr::AT_EnableIf:
- handleEnableIfAttr(S, D, AL);
- break;
- case ParsedAttr::AT_DiagnoseIf:
- handleDiagnoseIfAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ExtVectorType:
- handleExtVectorTypeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ExternalSourceSymbol:
- handleExternalSourceSymbolAttr(S, D, AL);
- break;
- case ParsedAttr::AT_MinSize:
- handleMinSizeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_OptimizeNone:
- handleOptimizeNoneAttr(S, D, AL);
- break;
- case ParsedAttr::AT_FlagEnum:
- handleSimpleAttribute<FlagEnumAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_EnumExtensibility:
- handleEnumExtensibilityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Flatten:
- handleSimpleAttribute<FlattenAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Format:
- handleFormatAttr(S, D, AL);
- break;
- case ParsedAttr::AT_FormatArg:
- handleFormatArgAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Callback:
- handleCallbackAttr(S, D, AL);
- break;
- case ParsedAttr::AT_CUDAGlobal:
- handleGlobalAttr(S, D, AL);
- break;
- case ParsedAttr::AT_CUDADevice:
- handleSimpleAttributeWithExclusions<CUDADeviceAttr, CUDAGlobalAttr>(S, D,
- AL);
- break;
- case ParsedAttr::AT_CUDAHost:
- handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_HIPPinnedShadow:
- handleSimpleAttributeWithExclusions<HIPPinnedShadowAttr, CUDADeviceAttr,
- CUDAConstantAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_GNUInline:
- handleGNUInlineAttr(S, D, AL);
- break;
- case ParsedAttr::AT_CUDALaunchBounds:
- handleLaunchBoundsAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Restrict:
- handleRestrictAttr(S, D, AL);
- break;
- case ParsedAttr::AT_LifetimeBound:
- handleSimpleAttribute<LifetimeBoundAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_MayAlias:
- handleSimpleAttribute<MayAliasAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Mode:
- handleModeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoAlias:
- handleSimpleAttribute<NoAliasAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoCommon:
- handleSimpleAttribute<NoCommonAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoSplitStack:
- handleSimpleAttribute<NoSplitStackAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoUniqueAddress:
- handleSimpleAttribute<NoUniqueAddressAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NonNull:
- if (auto *PVD = dyn_cast<ParmVarDecl>(D))
- handleNonNullAttrParameter(S, PVD, AL);
- else
- handleNonNullAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ReturnsNonNull:
- handleReturnsNonNullAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoEscape:
- handleNoEscapeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AssumeAligned:
- handleAssumeAlignedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AllocAlign:
- handleAllocAlignAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Overloadable:
- handleSimpleAttribute<OverloadableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Ownership:
- handleOwnershipAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Cold:
- handleSimpleAttributeWithExclusions<ColdAttr, HotAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Hot:
- handleSimpleAttributeWithExclusions<HotAttr, ColdAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Naked:
- handleNakedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoReturn:
- handleNoReturnAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AnyX86NoCfCheck:
- handleNoCfCheckAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoThrow:
- if (!AL.isUsedAsTypeAttr())
- handleSimpleAttribute<NoThrowAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_CUDAShared:
- handleSharedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_VecReturn:
- handleVecReturnAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCOwnership:
- handleObjCOwnershipAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCPreciseLifetime:
- handleObjCPreciseLifetimeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCReturnsInnerPointer:
- handleObjCReturnsInnerPointerAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCRequiresSuper:
- handleObjCRequiresSuperAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCBridge:
- handleObjCBridgeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCBridgeMutable:
- handleObjCBridgeMutableAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCBridgeRelated:
- handleObjCBridgeRelatedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCDesignatedInitializer:
- handleObjCDesignatedInitializer(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCRuntimeName:
- handleObjCRuntimeName(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCRuntimeVisible:
- handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCBoxable:
- handleObjCBoxable(S, D, AL);
- break;
- case ParsedAttr::AT_CFAuditedTransfer:
- handleSimpleAttributeWithExclusions<CFAuditedTransferAttr,
- CFUnknownTransferAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_CFUnknownTransfer:
- handleSimpleAttributeWithExclusions<CFUnknownTransferAttr,
- CFAuditedTransferAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_CFConsumed:
- case ParsedAttr::AT_NSConsumed:
- case ParsedAttr::AT_OSConsumed:
- S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL),
- /*IsTemplateInstantiation=*/false);
- break;
- case ParsedAttr::AT_NSConsumesSelf:
- handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_OSConsumesThis:
- handleSimpleAttribute<OSConsumesThisAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_OSReturnsRetainedOnZero:
- handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnZeroAttr>(
- S, D, AL, isValidOSObjectOutParameter(D),
- diag::warn_ns_attribute_wrong_parameter_type,
- /*Extra Args=*/AL, /*pointer-to-OSObject-pointer*/ 3, AL.getRange());
- break;
- case ParsedAttr::AT_OSReturnsRetainedOnNonZero:
- handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnNonZeroAttr>(
- S, D, AL, isValidOSObjectOutParameter(D),
- diag::warn_ns_attribute_wrong_parameter_type,
- /*Extra Args=*/AL, /*pointer-to-OSObject-poointer*/ 3, AL.getRange());
- break;
- case ParsedAttr::AT_NSReturnsAutoreleased:
- case ParsedAttr::AT_NSReturnsNotRetained:
- case ParsedAttr::AT_NSReturnsRetained:
- case ParsedAttr::AT_CFReturnsNotRetained:
- case ParsedAttr::AT_CFReturnsRetained:
- case ParsedAttr::AT_OSReturnsNotRetained:
- case ParsedAttr::AT_OSReturnsRetained:
- handleXReturnsXRetainedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_WorkGroupSizeHint:
- handleWorkGroupSize<WorkGroupSizeHintAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ReqdWorkGroupSize:
- handleWorkGroupSize<ReqdWorkGroupSizeAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_OpenCLIntelReqdSubGroupSize:
- handleSubGroupSize(S, D, AL);
- break;
- case ParsedAttr::AT_VecTypeHint:
- handleVecTypeHint(S, D, AL);
- break;
- case ParsedAttr::AT_ConstInit:
- handleSimpleAttribute<ConstInitAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_InitPriority:
- handleInitPriorityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Packed:
- handlePackedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Section:
- handleSectionAttr(S, D, AL);
- break;
- case ParsedAttr::AT_SpeculativeLoadHardening:
- handleSimpleAttributeWithExclusions<SpeculativeLoadHardeningAttr,
- NoSpeculativeLoadHardeningAttr>(S, D,
- AL);
- break;
- case ParsedAttr::AT_NoSpeculativeLoadHardening:
- handleSimpleAttributeWithExclusions<NoSpeculativeLoadHardeningAttr,
- SpeculativeLoadHardeningAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_CodeSeg:
- handleCodeSegAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Target:
- handleTargetAttr(S, D, AL);
- break;
- case ParsedAttr::AT_MinVectorWidth:
- handleMinVectorWidthAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Unavailable:
- handleAttrWithMessage<UnavailableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ArcWeakrefUnavailable:
- handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCRootClass:
- handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCNonLazyClass:
- handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCSubclassingRestricted:
- handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCClassStub:
- handleSimpleAttribute<ObjCClassStubAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCExplicitProtocolImpl:
- handleObjCSuppresProtocolAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCRequiresPropertyDefs:
- handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Unused:
- handleUnusedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ReturnsTwice:
- handleSimpleAttribute<ReturnsTwiceAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NotTailCalled:
- handleSimpleAttributeWithExclusions<NotTailCalledAttr, AlwaysInlineAttr>(
- S, D, AL);
- break;
- case ParsedAttr::AT_DisableTailCalls:
- handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D,
- AL);
- break;
- case ParsedAttr::AT_Used:
- handleSimpleAttribute<UsedAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Visibility:
- handleVisibilityAttr(S, D, AL, false);
- break;
- case ParsedAttr::AT_TypeVisibility:
- handleVisibilityAttr(S, D, AL, true);
- break;
- case ParsedAttr::AT_WarnUnused:
- handleSimpleAttribute<WarnUnusedAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_WarnUnusedResult:
- handleWarnUnusedResult(S, D, AL);
- break;
- case ParsedAttr::AT_Weak:
- handleSimpleAttribute<WeakAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_WeakRef:
- handleWeakRefAttr(S, D, AL);
- break;
- case ParsedAttr::AT_WeakImport:
- handleWeakImportAttr(S, D, AL);
- break;
- case ParsedAttr::AT_TransparentUnion:
- handleTransparentUnionAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCException:
- handleSimpleAttribute<ObjCExceptionAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCMethodFamily:
- handleObjCMethodFamilyAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCNSObject:
- handleObjCNSObject(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCIndependentClass:
- handleObjCIndependentClass(S, D, AL);
- break;
- case ParsedAttr::AT_Blocks:
- handleBlocksAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Sentinel:
- handleSentinelAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Const:
- handleSimpleAttribute<ConstAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Pure:
- handleSimpleAttribute<PureAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Cleanup:
- handleCleanupAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoDebug:
- handleNoDebugAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoDuplicate:
- handleSimpleAttribute<NoDuplicateAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Convergent:
- handleSimpleAttribute<ConvergentAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoInline:
- handleSimpleAttribute<NoInlineAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoInstrumentFunction: // Interacts with -pg.
- handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoStackProtector:
- // Interacts with -fstack-protector options.
- handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_CFICanonicalJumpTable:
- handleSimpleAttribute<CFICanonicalJumpTableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_StdCall:
- case ParsedAttr::AT_CDecl:
- case ParsedAttr::AT_FastCall:
- case ParsedAttr::AT_ThisCall:
- case ParsedAttr::AT_Pascal:
- case ParsedAttr::AT_RegCall:
- case ParsedAttr::AT_SwiftCall:
- case ParsedAttr::AT_VectorCall:
- case ParsedAttr::AT_MSABI:
- case ParsedAttr::AT_SysVABI:
- case ParsedAttr::AT_Pcs:
- case ParsedAttr::AT_IntelOclBicc:
- case ParsedAttr::AT_PreserveMost:
- case ParsedAttr::AT_PreserveAll:
- case ParsedAttr::AT_AArch64VectorPcs:
- handleCallConvAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Suppress:
- handleSuppressAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Owner:
- case ParsedAttr::AT_Pointer:
- handleLifetimeCategoryAttr(S, D, AL);
- break;
- case ParsedAttr::AT_OpenCLKernel:
- handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_OpenCLAccess:
- handleOpenCLAccessAttr(S, D, AL);
- break;
- case ParsedAttr::AT_OpenCLNoSVM:
- handleOpenCLNoSVMAttr(S, D, AL);
- break;
- case ParsedAttr::AT_SwiftContext:
- S.AddParameterABIAttr(D, AL, ParameterABI::SwiftContext);
- break;
- case ParsedAttr::AT_SwiftErrorResult:
- S.AddParameterABIAttr(D, AL, ParameterABI::SwiftErrorResult);
- break;
- case ParsedAttr::AT_SwiftIndirectResult:
- S.AddParameterABIAttr(D, AL, ParameterABI::SwiftIndirectResult);
- break;
- case ParsedAttr::AT_InternalLinkage:
- handleInternalLinkageAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ExcludeFromExplicitInstantiation:
- handleSimpleAttribute<ExcludeFromExplicitInstantiationAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_LTOVisibilityPublic:
- handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL);
- break;
- // Microsoft attributes:
- case ParsedAttr::AT_EmptyBases:
- handleSimpleAttribute<EmptyBasesAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_LayoutVersion:
- handleLayoutVersion(S, D, AL);
- break;
- case ParsedAttr::AT_TrivialABI:
- handleSimpleAttribute<TrivialABIAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_MSNoVTable:
- handleSimpleAttribute<MSNoVTableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_MSStruct:
- handleSimpleAttribute<MSStructAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Uuid:
- handleUuidAttr(S, D, AL);
- break;
- case ParsedAttr::AT_MSInheritance:
- handleMSInheritanceAttr(S, D, AL);
- break;
- case ParsedAttr::AT_SelectAny:
- handleSimpleAttribute<SelectAnyAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_Thread:
- handleDeclspecThreadAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AbiTag:
- handleAbiTagAttr(S, D, AL);
- break;
- // Thread safety attributes:
- case ParsedAttr::AT_AssertExclusiveLock:
- handleAssertExclusiveLockAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AssertSharedLock:
- handleAssertSharedLockAttr(S, D, AL);
- break;
- case ParsedAttr::AT_GuardedVar:
- handleSimpleAttribute<GuardedVarAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_PtGuardedVar:
- handlePtGuardedVarAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ScopedLockable:
- handleSimpleAttribute<ScopedLockableAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_NoSanitize:
- handleNoSanitizeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoSanitizeSpecific:
- handleNoSanitizeSpecificAttr(S, D, AL);
- break;
- case ParsedAttr::AT_NoThreadSafetyAnalysis:
- handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_GuardedBy:
- handleGuardedByAttr(S, D, AL);
- break;
- case ParsedAttr::AT_PtGuardedBy:
- handlePtGuardedByAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ExclusiveTrylockFunction:
- handleExclusiveTrylockFunctionAttr(S, D, AL);
- break;
- case ParsedAttr::AT_LockReturned:
- handleLockReturnedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_LocksExcluded:
- handleLocksExcludedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_SharedTrylockFunction:
- handleSharedTrylockFunctionAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AcquiredBefore:
- handleAcquiredBeforeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AcquiredAfter:
- handleAcquiredAfterAttr(S, D, AL);
- break;
- // Capability analysis attributes.
- case ParsedAttr::AT_Capability:
- case ParsedAttr::AT_Lockable:
- handleCapabilityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_RequiresCapability:
- handleRequiresCapabilityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AssertCapability:
- handleAssertCapabilityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AcquireCapability:
- handleAcquireCapabilityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ReleaseCapability:
- handleReleaseCapabilityAttr(S, D, AL);
- break;
- case ParsedAttr::AT_TryAcquireCapability:
- handleTryAcquireCapabilityAttr(S, D, AL);
- break;
- // Consumed analysis attributes.
- case ParsedAttr::AT_Consumable:
- handleConsumableAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ConsumableAutoCast:
- handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_ConsumableSetOnRead:
- handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_CallableWhen:
- handleCallableWhenAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ParamTypestate:
- handleParamTypestateAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ReturnTypestate:
- handleReturnTypestateAttr(S, D, AL);
- break;
- case ParsedAttr::AT_SetTypestate:
- handleSetTypestateAttr(S, D, AL);
- break;
- case ParsedAttr::AT_TestTypestate:
- handleTestTypestateAttr(S, D, AL);
- break;
- // Type safety attributes.
- case ParsedAttr::AT_ArgumentWithTypeTag:
- handleArgumentWithTypeTagAttr(S, D, AL);
- break;
- case ParsedAttr::AT_TypeTagForDatatype:
- handleTypeTagForDatatypeAttr(S, D, AL);
- break;
- case ParsedAttr::AT_AnyX86NoCallerSavedRegisters:
- handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_RenderScriptKernel:
- handleSimpleAttribute<RenderScriptKernelAttr>(S, D, AL);
- break;
- // XRay attributes.
- case ParsedAttr::AT_XRayInstrument:
- handleSimpleAttribute<XRayInstrumentAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_XRayLogArgs:
- handleXRayLogArgsAttr(S, D, AL);
- break;
- // Move semantics attribute.
- case ParsedAttr::AT_Reinitializes:
- handleSimpleAttribute<ReinitializesAttr>(S, D, AL);
- break;
- case ParsedAttr::AT_AlwaysDestroy:
- case ParsedAttr::AT_NoDestroy:
- handleDestroyAttr(S, D, AL);
- break;
- case ParsedAttr::AT_Uninitialized:
- handleUninitializedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_ObjCExternallyRetained:
- handleObjCExternallyRetainedAttr(S, D, AL);
- break;
- case ParsedAttr::AT_MIGServerRoutine:
- handleMIGServerRoutineAttr(S, D, AL);
- break;
- case ParsedAttr::AT_MSAllocator:
- handleMSAllocatorAttr(S, D, AL);
- break;
- }
- }
- /// ProcessDeclAttributeList - Apply all the decl attributes in the specified
- /// attribute list to the specified decl, ignoring any type attributes.
- void Sema::ProcessDeclAttributeList(Scope *S, Decl *D,
- const ParsedAttributesView &AttrList,
- bool IncludeCXX11Attributes) {
- if (AttrList.empty())
- return;
- for (const ParsedAttr &AL : AttrList)
- ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes);
- // FIXME: We should be able to handle these cases in TableGen.
- // GCC accepts
- // static int a9 __attribute__((weakref));
- // but that looks really pointless. We reject it.
- if (D->hasAttr<WeakRefAttr>() && !D->hasAttr<AliasAttr>()) {
- Diag(AttrList.begin()->getLoc(), diag::err_attribute_weakref_without_alias)
- << cast<NamedDecl>(D);
- D->dropAttr<WeakRefAttr>();
- return;
- }
- // FIXME: We should be able to handle this in TableGen as well. It would be
- // good to have a way to specify "these attributes must appear as a group",
- // for these. Additionally, it would be good to have a way to specify "these
- // attribute must never appear as a group" for attributes like cold and hot.
- if (!D->hasAttr<OpenCLKernelAttr>()) {
- // These attributes cannot be applied to a non-kernel function.
- if (const auto *A = D->getAttr<ReqdWorkGroupSizeAttr>()) {
- // FIXME: This emits a different error message than
- // diag::err_attribute_wrong_decl_type + ExpectedKernelFunction.
- Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
- D->setInvalidDecl();
- } else if (const auto *A = D->getAttr<WorkGroupSizeHintAttr>()) {
- Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
- D->setInvalidDecl();
- } else if (const auto *A = D->getAttr<VecTypeHintAttr>()) {
- Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
- D->setInvalidDecl();
- } else if (const auto *A = D->getAttr<OpenCLIntelReqdSubGroupSizeAttr>()) {
- Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A;
- D->setInvalidDecl();
- } else if (!D->hasAttr<CUDAGlobalAttr>()) {
- if (const auto *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) {
- Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << A << ExpectedKernelFunction;
- D->setInvalidDecl();
- } else if (const auto *A = D->getAttr<AMDGPUWavesPerEUAttr>()) {
- Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << A << ExpectedKernelFunction;
- D->setInvalidDecl();
- } else if (const auto *A = D->getAttr<AMDGPUNumSGPRAttr>()) {
- Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << A << ExpectedKernelFunction;
- D->setInvalidDecl();
- } else if (const auto *A = D->getAttr<AMDGPUNumVGPRAttr>()) {
- Diag(D->getLocation(), diag::err_attribute_wrong_decl_type)
- << A << ExpectedKernelFunction;
- D->setInvalidDecl();
- }
- }
- }
- // Do this check after processing D's attributes because the attribute
- // objc_method_family can change whether the given method is in the init
- // family, and it can be applied after objc_designated_initializer. This is a
- // bit of a hack, but we need it to be compatible with versions of clang that
- // processed the attribute list in the wrong order.
- if (D->hasAttr<ObjCDesignatedInitializerAttr>() &&
- cast<ObjCMethodDecl>(D)->getMethodFamily() != OMF_init) {
- Diag(D->getLocation(), diag::err_designated_init_attr_non_init);
- D->dropAttr<ObjCDesignatedInitializerAttr>();
- }
- }
- // Helper for delayed processing TransparentUnion attribute.
- void Sema::ProcessDeclAttributeDelayed(Decl *D,
- const ParsedAttributesView &AttrList) {
- for (const ParsedAttr &AL : AttrList)
- if (AL.getKind() == ParsedAttr::AT_TransparentUnion) {
- handleTransparentUnionAttr(*this, D, AL);
- break;
- }
- }
- // Annotation attributes are the only attributes allowed after an access
- // specifier.
- bool Sema::ProcessAccessDeclAttributeList(
- AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) {
- for (const ParsedAttr &AL : AttrList) {
- if (AL.getKind() == ParsedAttr::AT_Annotate) {
- ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute());
- } else {
- Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec);
- return true;
- }
- }
- return false;
- }
- /// checkUnusedDeclAttributes - Check a list of attributes to see if it
- /// contains any decl attributes that we should warn about.
- static void checkUnusedDeclAttributes(Sema &S, const ParsedAttributesView &A) {
- for (const ParsedAttr &AL : A) {
- // Only warn if the attribute is an unignored, non-type attribute.
- if (AL.isUsedAsTypeAttr() || AL.isInvalid())
- continue;
- if (AL.getKind() == ParsedAttr::IgnoredAttribute)
- continue;
- if (AL.getKind() == ParsedAttr::UnknownAttribute) {
- S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
- << AL << AL.getRange();
- } else {
- S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL
- << AL.getRange();
- }
- }
- }
- /// checkUnusedDeclAttributes - Given a declarator which is not being
- /// used to build a declaration, complain about any decl attributes
- /// which might be lying around on it.
- void Sema::checkUnusedDeclAttributes(Declarator &D) {
- ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes());
- ::checkUnusedDeclAttributes(*this, D.getAttributes());
- for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i)
- ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs());
- }
- /// DeclClonePragmaWeak - clone existing decl (maybe definition),
- /// \#pragma weak needs a non-definition decl and source may not have one.
- NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II,
- SourceLocation Loc) {
- assert(isa<FunctionDecl>(ND) || isa<VarDecl>(ND));
- NamedDecl *NewD = nullptr;
- if (auto *FD = dyn_cast<FunctionDecl>(ND)) {
- FunctionDecl *NewFD;
- // FIXME: Missing call to CheckFunctionDeclaration().
- // FIXME: Mangling?
- // FIXME: Is the qualifier info correct?
- // FIXME: Is the DeclContext correct?
- NewFD = FunctionDecl::Create(
- FD->getASTContext(), FD->getDeclContext(), Loc, Loc,
- DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None,
- false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified);
- NewD = NewFD;
- if (FD->getQualifier())
- NewFD->setQualifierInfo(FD->getQualifierLoc());
- // Fake up parameter variables; they are declared as if this were
- // a typedef.
- QualType FDTy = FD->getType();
- if (const auto *FT = FDTy->getAs<FunctionProtoType>()) {
- SmallVector<ParmVarDecl*, 16> Params;
- for (const auto &AI : FT->param_types()) {
- ParmVarDecl *Param = BuildParmVarDeclForTypedef(NewFD, Loc, AI);
- Param->setScopeInfo(0, Params.size());
- Params.push_back(Param);
- }
- NewFD->setParams(Params);
- }
- } else if (auto *VD = dyn_cast<VarDecl>(ND)) {
- NewD = VarDecl::Create(VD->getASTContext(), VD->getDeclContext(),
- VD->getInnerLocStart(), VD->getLocation(), II,
- VD->getType(), VD->getTypeSourceInfo(),
- VD->getStorageClass());
- if (VD->getQualifier())
- cast<VarDecl>(NewD)->setQualifierInfo(VD->getQualifierLoc());
- }
- return NewD;
- }
- /// DeclApplyPragmaWeak - A declaration (maybe definition) needs \#pragma weak
- /// applied to it, possibly with an alias.
- void Sema::DeclApplyPragmaWeak(Scope *S, NamedDecl *ND, WeakInfo &W) {
- if (W.getUsed()) return; // only do this once
- W.setUsed(true);
- if (W.getAlias()) { // clone decl, impersonate __attribute(weak,alias(...))
- IdentifierInfo *NDId = ND->getIdentifier();
- NamedDecl *NewD = DeclClonePragmaWeak(ND, W.getAlias(), W.getLocation());
- NewD->addAttr(
- AliasAttr::CreateImplicit(Context, NDId->getName(), W.getLocation()));
- NewD->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
- AttributeCommonInfo::AS_Pragma));
- WeakTopLevelDecl.push_back(NewD);
- // FIXME: "hideous" code from Sema::LazilyCreateBuiltin
- // to insert Decl at TU scope, sorry.
- DeclContext *SavedContext = CurContext;
- CurContext = Context.getTranslationUnitDecl();
- NewD->setDeclContext(CurContext);
- NewD->setLexicalDeclContext(CurContext);
- PushOnScopeChains(NewD, S);
- CurContext = SavedContext;
- } else { // just add weak to existing
- ND->addAttr(WeakAttr::CreateImplicit(Context, W.getLocation(),
- AttributeCommonInfo::AS_Pragma));
- }
- }
- void Sema::ProcessPragmaWeak(Scope *S, Decl *D) {
- // It's valid to "forward-declare" #pragma weak, in which case we
- // have to do this.
- LoadExternalWeakUndeclaredIdentifiers();
- if (!WeakUndeclaredIdentifiers.empty()) {
- NamedDecl *ND = nullptr;
- if (auto *VD = dyn_cast<VarDecl>(D))
- if (VD->isExternC())
- ND = VD;
- if (auto *FD = dyn_cast<FunctionDecl>(D))
- if (FD->isExternC())
- ND = FD;
- if (ND) {
- if (IdentifierInfo *Id = ND->getIdentifier()) {
- auto I = WeakUndeclaredIdentifiers.find(Id);
- if (I != WeakUndeclaredIdentifiers.end()) {
- WeakInfo W = I->second;
- DeclApplyPragmaWeak(S, ND, W);
- WeakUndeclaredIdentifiers[Id] = W;
- }
- }
- }
- }
- }
- /// ProcessDeclAttributes - Given a declarator (PD) with attributes indicated in
- /// it, apply them to D. This is a bit tricky because PD can have attributes
- /// specified in many different places, and we need to find and apply them all.
- void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {
- // Apply decl attributes from the DeclSpec if present.
- if (!PD.getDeclSpec().getAttributes().empty())
- ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes());
- // Walk the declarator structure, applying decl attributes that were in a type
- // position to the decl itself. This handles cases like:
- // int *__attr__(x)** D;
- // when X is a decl attribute.
- for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i)
- ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(),
- /*IncludeCXX11Attributes=*/false);
- // Finally, apply any attributes on the decl itself.
- ProcessDeclAttributeList(S, D, PD.getAttributes());
- // Apply additional attributes specified by '#pragma clang attribute'.
- AddPragmaAttributes(S, D);
- }
- /// Is the given declaration allowed to use a forbidden type?
- /// If so, it'll still be annotated with an attribute that makes it
- /// illegal to actually use.
- static bool isForbiddenTypeAllowed(Sema &S, Decl *D,
- const DelayedDiagnostic &diag,
- UnavailableAttr::ImplicitReason &reason) {
- // Private ivars are always okay. Unfortunately, people don't
- // always properly make their ivars private, even in system headers.
- // Plus we need to make fields okay, too.
- if (!isa<FieldDecl>(D) && !isa<ObjCPropertyDecl>(D) &&
- !isa<FunctionDecl>(D))
- return false;
- // Silently accept unsupported uses of __weak in both user and system
- // declarations when it's been disabled, for ease of integration with
- // -fno-objc-arc files. We do have to take some care against attempts
- // to define such things; for now, we've only done that for ivars
- // and properties.
- if ((isa<ObjCIvarDecl>(D) || isa<ObjCPropertyDecl>(D))) {
- if (diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_disabled ||
- diag.getForbiddenTypeDiagnostic() == diag::err_arc_weak_no_runtime) {
- reason = UnavailableAttr::IR_ForbiddenWeak;
- return true;
- }
- }
- // Allow all sorts of things in system headers.
- if (S.Context.getSourceManager().isInSystemHeader(D->getLocation())) {
- // Currently, all the failures dealt with this way are due to ARC
- // restrictions.
- reason = UnavailableAttr::IR_ARCForbiddenType;
- return true;
- }
- return false;
- }
- /// Handle a delayed forbidden-type diagnostic.
- static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &DD,
- Decl *D) {
- auto Reason = UnavailableAttr::IR_None;
- if (D && isForbiddenTypeAllowed(S, D, DD, Reason)) {
- assert(Reason && "didn't set reason?");
- D->addAttr(UnavailableAttr::CreateImplicit(S.Context, "", Reason, DD.Loc));
- return;
- }
- if (S.getLangOpts().ObjCAutoRefCount)
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
- // FIXME: we may want to suppress diagnostics for all
- // kind of forbidden type messages on unavailable functions.
- if (FD->hasAttr<UnavailableAttr>() &&
- DD.getForbiddenTypeDiagnostic() ==
- diag::err_arc_array_param_no_ownership) {
- DD.Triggered = true;
- return;
- }
- }
- S.Diag(DD.Loc, DD.getForbiddenTypeDiagnostic())
- << DD.getForbiddenTypeOperand() << DD.getForbiddenTypeArgument();
- DD.Triggered = true;
- }
- static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
- const Decl *D) {
- // Check each AvailabilityAttr to find the one for this platform.
- for (const auto *A : D->attrs()) {
- if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
- // FIXME: this is copied from CheckAvailability. We should try to
- // de-duplicate.
- // Check if this is an App Extension "platform", and if so chop off
- // the suffix for matching with the actual platform.
- StringRef ActualPlatform = Avail->getPlatform()->getName();
- StringRef RealizedPlatform = ActualPlatform;
- if (Context.getLangOpts().AppExt) {
- size_t suffix = RealizedPlatform.rfind("_app_extension");
- if (suffix != StringRef::npos)
- RealizedPlatform = RealizedPlatform.slice(0, suffix);
- }
- StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
- // Match the platform name.
- if (RealizedPlatform == TargetPlatform)
- return Avail;
- }
- }
- return nullptr;
- }
- /// The diagnostic we should emit for \c D, and the declaration that
- /// originated it, or \c AR_Available.
- ///
- /// \param D The declaration to check.
- /// \param Message If non-null, this will be populated with the message from
- /// the availability attribute that is selected.
- /// \param ClassReceiver If we're checking the the method of a class message
- /// send, the class. Otherwise nullptr.
- static std::pair<AvailabilityResult, const NamedDecl *>
- ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
- std::string *Message,
- ObjCInterfaceDecl *ClassReceiver) {
- AvailabilityResult Result = D->getAvailability(Message);
- // For typedefs, if the typedef declaration appears available look
- // to the underlying type to see if it is more restrictive.
- while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) {
- if (Result == AR_Available) {
- if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) {
- D = TT->getDecl();
- Result = D->getAvailability(Message);
- continue;
- }
- }
- break;
- }
- // Forward class declarations get their attributes from their definition.
- if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
- if (IDecl->getDefinition()) {
- D = IDecl->getDefinition();
- Result = D->getAvailability(Message);
- }
- }
- if (const auto *ECD = dyn_cast<EnumConstantDecl>(D))
- if (Result == AR_Available) {
- const DeclContext *DC = ECD->getDeclContext();
- if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) {
- Result = TheEnumDecl->getAvailability(Message);
- D = TheEnumDecl;
- }
- }
- // For +new, infer availability from -init.
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (S.NSAPIObj && ClassReceiver) {
- ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
- S.NSAPIObj->getInitSelector());
- if (Init && Result == AR_Available && MD->isClassMethod() &&
- MD->getSelector() == S.NSAPIObj->getNewSelector() &&
- MD->definedInNSObject(S.getASTContext())) {
- Result = Init->getAvailability(Message);
- D = Init;
- }
- }
- }
- return {Result, D};
- }
- /// whether we should emit a diagnostic for \c K and \c DeclVersion in
- /// the context of \c Ctx. For example, we should emit an unavailable diagnostic
- /// in a deprecated context, but not the other way around.
- static bool
- ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
- VersionTuple DeclVersion, Decl *Ctx,
- const NamedDecl *OffendingDecl) {
- assert(K != AR_Available && "Expected an unavailable declaration here!");
- // Checks if we should emit the availability diagnostic in the context of C.
- auto CheckContext = [&](const Decl *C) {
- if (K == AR_NotYetIntroduced) {
- if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
- if (AA->getIntroduced() >= DeclVersion)
- return true;
- } else if (K == AR_Deprecated) {
- if (C->isDeprecated())
- return true;
- } else if (K == AR_Unavailable) {
- // It is perfectly fine to refer to an 'unavailable' Objective-C method
- // when it is referenced from within the @implementation itself. In this
- // context, we interpret unavailable as a form of access control.
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) {
- if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) {
- if (MD->getClassInterface() == Impl->getClassInterface())
- return true;
- }
- }
- }
- if (C->isUnavailable())
- return true;
- return false;
- };
- do {
- if (CheckContext(Ctx))
- return false;
- // An implementation implicitly has the availability of the interface.
- // Unless it is "+load" method.
- if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx))
- if (MethodD->isClassMethod() &&
- MethodD->getSelector().getAsString() == "load")
- return true;
- if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) {
- if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface())
- if (CheckContext(Interface))
- return false;
- }
- // A category implicitly has the availability of the interface.
- else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx))
- if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface())
- if (CheckContext(Interface))
- return false;
- } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext())));
- return true;
- }
- static bool
- shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
- const VersionTuple &DeploymentVersion,
- const VersionTuple &DeclVersion) {
- const auto &Triple = Context.getTargetInfo().getTriple();
- VersionTuple ForceAvailabilityFromVersion;
- switch (Triple.getOS()) {
- case llvm::Triple::IOS:
- case llvm::Triple::TvOS:
- ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
- break;
- case llvm::Triple::WatchOS:
- ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4);
- break;
- case llvm::Triple::Darwin:
- case llvm::Triple::MacOSX:
- ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
- break;
- default:
- // New targets should always warn about availability.
- return Triple.getVendor() == llvm::Triple::Apple;
- }
- return DeploymentVersion >= ForceAvailabilityFromVersion ||
- DeclVersion >= ForceAvailabilityFromVersion;
- }
- static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
- for (Decl *Ctx = OrigCtx; Ctx;
- Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) {
- if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx))
- return cast<NamedDecl>(Ctx);
- if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) {
- if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx))
- return Imp->getClassInterface();
- return CD;
- }
- }
- return dyn_cast<NamedDecl>(OrigCtx);
- }
- namespace {
- struct AttributeInsertion {
- StringRef Prefix;
- SourceLocation Loc;
- StringRef Suffix;
- static AttributeInsertion createInsertionAfter(const NamedDecl *D) {
- return {" ", D->getEndLoc(), ""};
- }
- static AttributeInsertion createInsertionAfter(SourceLocation Loc) {
- return {" ", Loc, ""};
- }
- static AttributeInsertion createInsertionBefore(const NamedDecl *D) {
- return {"", D->getBeginLoc(), "\n"};
- }
- };
- } // end anonymous namespace
- /// Tries to parse a string as ObjC method name.
- ///
- /// \param Name The string to parse. Expected to originate from availability
- /// attribute argument.
- /// \param SlotNames The vector that will be populated with slot names. In case
- /// of unsuccessful parsing can contain invalid data.
- /// \returns A number of method parameters if parsing was successful, None
- /// otherwise.
- static Optional<unsigned>
- tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames,
- const LangOptions &LangOpts) {
- // Accept replacements starting with - or + as valid ObjC method names.
- if (!Name.empty() && (Name.front() == '-' || Name.front() == '+'))
- Name = Name.drop_front(1);
- if (Name.empty())
- return None;
- Name.split(SlotNames, ':');
- unsigned NumParams;
- if (Name.back() == ':') {
- // Remove an empty string at the end that doesn't represent any slot.
- SlotNames.pop_back();
- NumParams = SlotNames.size();
- } else {
- if (SlotNames.size() != 1)
- // Not a valid method name, just a colon-separated string.
- return None;
- NumParams = 0;
- }
- // Verify all slot names are valid.
- bool AllowDollar = LangOpts.DollarIdents;
- for (StringRef S : SlotNames) {
- if (S.empty())
- continue;
- if (!isValidIdentifier(S, AllowDollar))
- return None;
- }
- return NumParams;
- }
- /// Returns a source location in which it's appropriate to insert a new
- /// attribute for the given declaration \D.
- static Optional<AttributeInsertion>
- createAttributeInsertion(const NamedDecl *D, const SourceManager &SM,
- const LangOptions &LangOpts) {
- if (isa<ObjCPropertyDecl>(D))
- return AttributeInsertion::createInsertionAfter(D);
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (MD->hasBody())
- return None;
- return AttributeInsertion::createInsertionAfter(D);
- }
- if (const auto *TD = dyn_cast<TagDecl>(D)) {
- SourceLocation Loc =
- Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts);
- if (Loc.isInvalid())
- return None;
- // Insert after the 'struct'/whatever keyword.
- return AttributeInsertion::createInsertionAfter(Loc);
- }
- return AttributeInsertion::createInsertionBefore(D);
- }
- /// Actually emit an availability diagnostic for a reference to an unavailable
- /// decl.
- ///
- /// \param Ctx The context that the reference occurred in
- /// \param ReferringDecl The exact declaration that was referenced.
- /// \param OffendingDecl A related decl to \c ReferringDecl that has an
- /// availability attribute corresponding to \c K attached to it. Note that this
- /// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and
- /// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl
- /// and OffendingDecl is the EnumDecl.
- static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
- Decl *Ctx, const NamedDecl *ReferringDecl,
- const NamedDecl *OffendingDecl,
- StringRef Message,
- ArrayRef<SourceLocation> Locs,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess) {
- // Diagnostics for deprecated or unavailable.
- unsigned diag, diag_message, diag_fwdclass_message;
- unsigned diag_available_here = diag::note_availability_specified_here;
- SourceLocation NoteLocation = OffendingDecl->getLocation();
- // Matches 'diag::note_property_attribute' options.
- unsigned property_note_select;
- // Matches diag::note_availability_specified_here.
- unsigned available_here_select_kind;
- VersionTuple DeclVersion;
- if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
- DeclVersion = AA->getIntroduced();
- if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx,
- OffendingDecl))
- return;
- SourceLocation Loc = Locs.front();
- // The declaration can have multiple availability attributes, we are looking
- // at one of them.
- const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
- if (A && A->isInherited()) {
- for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
- Redecl = Redecl->getPreviousDecl()) {
- const AvailabilityAttr *AForRedecl =
- getAttrForPlatform(S.Context, Redecl);
- if (AForRedecl && !AForRedecl->isInherited()) {
- // If D is a declaration with inherited attributes, the note should
- // point to the declaration with actual attributes.
- NoteLocation = Redecl->getLocation();
- break;
- }
- }
- }
- switch (K) {
- case AR_NotYetIntroduced: {
- // We would like to emit the diagnostic even if -Wunguarded-availability is
- // not specified for deployment targets >= to iOS 11 or equivalent or
- // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
- // later.
- const AvailabilityAttr *AA =
- getAttrForPlatform(S.getASTContext(), OffendingDecl);
- VersionTuple Introduced = AA->getIntroduced();
- bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
- S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
- Introduced);
- unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability;
- std::string PlatformName = AvailabilityAttr::getPrettyPlatformName(
- S.getASTContext().getTargetInfo().getPlatformName());
- S.Diag(Loc, Warning) << OffendingDecl << PlatformName
- << Introduced.getAsString();
- S.Diag(OffendingDecl->getLocation(),
- diag::note_partial_availability_specified_here)
- << OffendingDecl << PlatformName << Introduced.getAsString()
- << S.Context.getTargetInfo().getPlatformMinVersion().getAsString();
- if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
- if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
- if (TD->getDeclName().isEmpty()) {
- S.Diag(TD->getLocation(),
- diag::note_decl_unguarded_availability_silence)
- << /*Anonymous*/ 1 << TD->getKindName();
- return;
- }
- auto FixitNoteDiag =
- S.Diag(Enclosing->getLocation(),
- diag::note_decl_unguarded_availability_silence)
- << /*Named*/ 0 << Enclosing;
- // Don't offer a fixit for declarations with availability attributes.
- if (Enclosing->hasAttr<AvailabilityAttr>())
- return;
- if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE"))
- return;
- Optional<AttributeInsertion> Insertion = createAttributeInsertion(
- Enclosing, S.getSourceManager(), S.getLangOpts());
- if (!Insertion)
- return;
- std::string PlatformName =
- AvailabilityAttr::getPlatformNameSourceSpelling(
- S.getASTContext().getTargetInfo().getPlatformName())
- .lower();
- std::string Introduced =
- OffendingDecl->getVersionIntroduced().getAsString();
- FixitNoteDiag << FixItHint::CreateInsertion(
- Insertion->Loc,
- (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName +
- "(" + Introduced + "))" + Insertion->Suffix)
- .str());
- }
- return;
- }
- case AR_Deprecated:
- diag = !ObjCPropertyAccess ? diag::warn_deprecated
- : diag::warn_property_method_deprecated;
- diag_message = diag::warn_deprecated_message;
- diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
- property_note_select = /* deprecated */ 0;
- available_here_select_kind = /* deprecated */ 2;
- if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>())
- NoteLocation = AL->getLocation();
- break;
- case AR_Unavailable:
- diag = !ObjCPropertyAccess ? diag::err_unavailable
- : diag::err_property_method_unavailable;
- diag_message = diag::err_unavailable_message;
- diag_fwdclass_message = diag::warn_unavailable_fwdclass_message;
- property_note_select = /* unavailable */ 1;
- available_here_select_kind = /* unavailable */ 0;
- if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) {
- if (AL->isImplicit() && AL->getImplicitReason()) {
- // Most of these failures are due to extra restrictions in ARC;
- // reflect that in the primary diagnostic when applicable.
- auto flagARCError = [&] {
- if (S.getLangOpts().ObjCAutoRefCount &&
- S.getSourceManager().isInSystemHeader(
- OffendingDecl->getLocation()))
- diag = diag::err_unavailable_in_arc;
- };
- switch (AL->getImplicitReason()) {
- case UnavailableAttr::IR_None: break;
- case UnavailableAttr::IR_ARCForbiddenType:
- flagARCError();
- diag_available_here = diag::note_arc_forbidden_type;
- break;
- case UnavailableAttr::IR_ForbiddenWeak:
- if (S.getLangOpts().ObjCWeakRuntime)
- diag_available_here = diag::note_arc_weak_disabled;
- else
- diag_available_here = diag::note_arc_weak_no_runtime;
- break;
- case UnavailableAttr::IR_ARCForbiddenConversion:
- flagARCError();
- diag_available_here = diag::note_performs_forbidden_arc_conversion;
- break;
- case UnavailableAttr::IR_ARCInitReturnsUnrelated:
- flagARCError();
- diag_available_here = diag::note_arc_init_returns_unrelated;
- break;
- case UnavailableAttr::IR_ARCFieldWithOwnership:
- flagARCError();
- diag_available_here = diag::note_arc_field_with_ownership;
- break;
- }
- }
- }
- break;
- case AR_Available:
- llvm_unreachable("Warning for availability of available declaration?");
- }
- SmallVector<FixItHint, 12> FixIts;
- if (K == AR_Deprecated) {
- StringRef Replacement;
- if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>())
- Replacement = AL->getReplacement();
- if (auto AL = getAttrForPlatform(S.Context, OffendingDecl))
- Replacement = AL->getReplacement();
- CharSourceRange UseRange;
- if (!Replacement.empty())
- UseRange =
- CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
- if (UseRange.isValid()) {
- if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) {
- Selector Sel = MethodDecl->getSelector();
- SmallVector<StringRef, 12> SelectorSlotNames;
- Optional<unsigned> NumParams = tryParseObjCMethodName(
- Replacement, SelectorSlotNames, S.getLangOpts());
- if (NumParams && NumParams.getValue() == Sel.getNumArgs()) {
- assert(SelectorSlotNames.size() == Locs.size());
- for (unsigned I = 0; I < Locs.size(); ++I) {
- if (!Sel.getNameForSlot(I).empty()) {
- CharSourceRange NameRange = CharSourceRange::getCharRange(
- Locs[I], S.getLocForEndOfToken(Locs[I]));
- FixIts.push_back(FixItHint::CreateReplacement(
- NameRange, SelectorSlotNames[I]));
- } else
- FixIts.push_back(
- FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I]));
- }
- } else
- FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
- } else
- FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement));
- }
- }
- if (!Message.empty()) {
- S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts;
- if (ObjCProperty)
- S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
- << ObjCProperty->getDeclName() << property_note_select;
- } else if (!UnknownObjCClass) {
- S.Diag(Loc, diag) << ReferringDecl << FixIts;
- if (ObjCProperty)
- S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
- << ObjCProperty->getDeclName() << property_note_select;
- } else {
- S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts;
- S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
- }
- S.Diag(NoteLocation, diag_available_here)
- << OffendingDecl << available_here_select_kind;
- }
- static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD,
- Decl *Ctx) {
- assert(DD.Kind == DelayedDiagnostic::Availability &&
- "Expected an availability diagnostic here");
- DD.Triggered = true;
- DoEmitAvailabilityWarning(
- S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(),
- DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(),
- DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(),
- DD.getObjCProperty(), false);
- }
- void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) {
- assert(DelayedDiagnostics.getCurrentPool());
- DelayedDiagnosticPool &poppedPool = *DelayedDiagnostics.getCurrentPool();
- DelayedDiagnostics.popWithoutEmitting(state);
- // When delaying diagnostics to run in the context of a parsed
- // declaration, we only want to actually emit anything if parsing
- // succeeds.
- if (!decl) return;
- // We emit all the active diagnostics in this pool or any of its
- // parents. In general, we'll get one pool for the decl spec
- // and a child pool for each declarator; in a decl group like:
- // deprecated_typedef foo, *bar, baz();
- // only the declarator pops will be passed decls. This is correct;
- // we really do need to consider delayed diagnostics from the decl spec
- // for each of the different declarations.
- const DelayedDiagnosticPool *pool = &poppedPool;
- do {
- bool AnyAccessFailures = false;
- for (DelayedDiagnosticPool::pool_iterator
- i = pool->pool_begin(), e = pool->pool_end(); i != e; ++i) {
- // This const_cast is a bit lame. Really, Triggered should be mutable.
- DelayedDiagnostic &diag = const_cast<DelayedDiagnostic&>(*i);
- if (diag.Triggered)
- continue;
- switch (diag.Kind) {
- case DelayedDiagnostic::Availability:
- // Don't bother giving deprecation/unavailable diagnostics if
- // the decl is invalid.
- if (!decl->isInvalidDecl())
- handleDelayedAvailabilityCheck(*this, diag, decl);
- break;
- case DelayedDiagnostic::Access:
- // Only produce one access control diagnostic for a structured binding
- // declaration: we don't need to tell the user that all the fields are
- // inaccessible one at a time.
- if (AnyAccessFailures && isa<DecompositionDecl>(decl))
- continue;
- HandleDelayedAccessCheck(diag, decl);
- if (diag.Triggered)
- AnyAccessFailures = true;
- break;
- case DelayedDiagnostic::ForbiddenType:
- handleDelayedForbiddenType(*this, diag, decl);
- break;
- }
- }
- } while ((pool = pool->getParent()));
- }
- /// Given a set of delayed diagnostics, re-emit them as if they had
- /// been delayed in the current context instead of in the given pool.
- /// Essentially, this just moves them to the current pool.
- void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) {
- DelayedDiagnosticPool *curPool = DelayedDiagnostics.getCurrentPool();
- assert(curPool && "re-emitting in undelayed context not supported");
- curPool->steal(pool);
- }
- static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR,
- const NamedDecl *ReferringDecl,
- const NamedDecl *OffendingDecl,
- StringRef Message,
- ArrayRef<SourceLocation> Locs,
- const ObjCInterfaceDecl *UnknownObjCClass,
- const ObjCPropertyDecl *ObjCProperty,
- bool ObjCPropertyAccess) {
- // Delay if we're currently parsing a declaration.
- if (S.DelayedDiagnostics.shouldDelayDiagnostics()) {
- S.DelayedDiagnostics.add(
- DelayedDiagnostic::makeAvailability(
- AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass,
- ObjCProperty, Message, ObjCPropertyAccess));
- return;
- }
- Decl *Ctx = cast<Decl>(S.getCurLexicalContext());
- DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl,
- Message, Locs, UnknownObjCClass, ObjCProperty,
- ObjCPropertyAccess);
- }
- namespace {
- /// Returns true if the given statement can be a body-like child of \p Parent.
- bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) {
- switch (Parent->getStmtClass()) {
- case Stmt::IfStmtClass:
- return cast<IfStmt>(Parent)->getThen() == S ||
- cast<IfStmt>(Parent)->getElse() == S;
- case Stmt::WhileStmtClass:
- return cast<WhileStmt>(Parent)->getBody() == S;
- case Stmt::DoStmtClass:
- return cast<DoStmt>(Parent)->getBody() == S;
- case Stmt::ForStmtClass:
- return cast<ForStmt>(Parent)->getBody() == S;
- case Stmt::CXXForRangeStmtClass:
- return cast<CXXForRangeStmt>(Parent)->getBody() == S;
- case Stmt::ObjCForCollectionStmtClass:
- return cast<ObjCForCollectionStmt>(Parent)->getBody() == S;
- case Stmt::CaseStmtClass:
- case Stmt::DefaultStmtClass:
- return cast<SwitchCase>(Parent)->getSubStmt() == S;
- default:
- return false;
- }
- }
- class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> {
- const Stmt *Target;
- public:
- bool VisitStmt(Stmt *S) { return S != Target; }
- /// Returns true if the given statement is present in the given declaration.
- static bool isContained(const Stmt *Target, const Decl *D) {
- StmtUSEFinder Visitor;
- Visitor.Target = Target;
- return !Visitor.TraverseDecl(const_cast<Decl *>(D));
- }
- };
- /// Traverses the AST and finds the last statement that used a given
- /// declaration.
- class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> {
- const Decl *D;
- public:
- bool VisitDeclRefExpr(DeclRefExpr *DRE) {
- if (DRE->getDecl() == D)
- return false;
- return true;
- }
- static const Stmt *findLastStmtThatUsesDecl(const Decl *D,
- const CompoundStmt *Scope) {
- LastDeclUSEFinder Visitor;
- Visitor.D = D;
- for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) {
- const Stmt *S = *I;
- if (!Visitor.TraverseStmt(const_cast<Stmt *>(S)))
- return S;
- }
- return nullptr;
- }
- };
- /// This class implements -Wunguarded-availability.
- ///
- /// This is done with a traversal of the AST of a function that makes reference
- /// to a partially available declaration. Whenever we encounter an \c if of the
- /// form: \c if(@available(...)), we use the version from the condition to visit
- /// the then statement.
- class DiagnoseUnguardedAvailability
- : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> {
- typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base;
- Sema &SemaRef;
- Decl *Ctx;
- /// Stack of potentially nested 'if (@available(...))'s.
- SmallVector<VersionTuple, 8> AvailabilityStack;
- SmallVector<const Stmt *, 16> StmtStack;
- void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range,
- ObjCInterfaceDecl *ClassReceiver = nullptr);
- public:
- DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx)
- : SemaRef(SemaRef), Ctx(Ctx) {
- AvailabilityStack.push_back(
- SemaRef.Context.getTargetInfo().getPlatformMinVersion());
- }
- bool TraverseDecl(Decl *D) {
- // Avoid visiting nested functions to prevent duplicate warnings.
- if (!D || isa<FunctionDecl>(D))
- return true;
- return Base::TraverseDecl(D);
- }
- bool TraverseStmt(Stmt *S) {
- if (!S)
- return true;
- StmtStack.push_back(S);
- bool Result = Base::TraverseStmt(S);
- StmtStack.pop_back();
- return Result;
- }
- void IssueDiagnostics(Stmt *S) { TraverseStmt(S); }
- bool TraverseIfStmt(IfStmt *If);
- bool TraverseLambdaExpr(LambdaExpr *E) { return true; }
- // for 'case X:' statements, don't bother looking at the 'X'; it can't lead
- // to any useful diagnostics.
- bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); }
- bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) {
- if (PRE->isClassReceiver())
- DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation());
- return true;
- }
- bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) {
- if (ObjCMethodDecl *D = Msg->getMethodDecl()) {
- ObjCInterfaceDecl *ID = nullptr;
- QualType ReceiverTy = Msg->getClassReceiver();
- if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType())
- ID = ReceiverTy->getAsObjCInterfaceType()->getInterface();
- DiagnoseDeclAvailability(
- D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID);
- }
- return true;
- }
- bool VisitDeclRefExpr(DeclRefExpr *DRE) {
- DiagnoseDeclAvailability(DRE->getDecl(),
- SourceRange(DRE->getBeginLoc(), DRE->getEndLoc()));
- return true;
- }
- bool VisitMemberExpr(MemberExpr *ME) {
- DiagnoseDeclAvailability(ME->getMemberDecl(),
- SourceRange(ME->getBeginLoc(), ME->getEndLoc()));
- return true;
- }
- bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) {
- SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use)
- << (!SemaRef.getLangOpts().ObjC);
- return true;
- }
- bool VisitTypeLoc(TypeLoc Ty);
- };
- void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
- NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) {
- AvailabilityResult Result;
- const NamedDecl *OffendingDecl;
- std::tie(Result, OffendingDecl) =
- ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass);
- if (Result != AR_Available) {
- // All other diagnostic kinds have already been handled in
- // DiagnoseAvailabilityOfDecl.
- if (Result != AR_NotYetIntroduced)
- return;
- const AvailabilityAttr *AA =
- getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
- VersionTuple Introduced = AA->getIntroduced();
- if (AvailabilityStack.back() >= Introduced)
- return;
- // If the context of this function is less available than D, we should not
- // emit a diagnostic.
- if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx,
- OffendingDecl))
- return;
- // We would like to emit the diagnostic even if -Wunguarded-availability is
- // not specified for deployment targets >= to iOS 11 or equivalent or
- // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
- // later.
- unsigned DiagKind =
- shouldDiagnoseAvailabilityByDefault(
- SemaRef.Context,
- SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
- ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability;
- std::string PlatformName = AvailabilityAttr::getPrettyPlatformName(
- SemaRef.getASTContext().getTargetInfo().getPlatformName());
- SemaRef.Diag(Range.getBegin(), DiagKind)
- << Range << D << PlatformName << Introduced.getAsString();
- SemaRef.Diag(OffendingDecl->getLocation(),
- diag::note_partial_availability_specified_here)
- << OffendingDecl << PlatformName << Introduced.getAsString()
- << SemaRef.Context.getTargetInfo()
- .getPlatformMinVersion()
- .getAsString();
- auto FixitDiag =
- SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
- << Range << D
- << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0
- : /*__builtin_available*/ 1);
- // Find the statement which should be enclosed in the if @available check.
- if (StmtStack.empty())
- return;
- const Stmt *StmtOfUse = StmtStack.back();
- const CompoundStmt *Scope = nullptr;
- for (const Stmt *S : llvm::reverse(StmtStack)) {
- if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
- Scope = CS;
- break;
- }
- if (isBodyLikeChildStmt(StmtOfUse, S)) {
- // The declaration won't be seen outside of the statement, so we don't
- // have to wrap the uses of any declared variables in if (@available).
- // Therefore we can avoid setting Scope here.
- break;
- }
- StmtOfUse = S;
- }
- const Stmt *LastStmtOfUse = nullptr;
- if (isa<DeclStmt>(StmtOfUse) && Scope) {
- for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) {
- if (StmtUSEFinder::isContained(StmtStack.back(), D)) {
- LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope);
- break;
- }
- }
- }
- const SourceManager &SM = SemaRef.getSourceManager();
- SourceLocation IfInsertionLoc =
- SM.getExpansionLoc(StmtOfUse->getBeginLoc());
- SourceLocation StmtEndLoc =
- SM.getExpansionRange(
- (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc())
- .getEnd();
- if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc))
- return;
- StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM);
- const char *ExtraIndentation = " ";
- std::string FixItString;
- llvm::raw_string_ostream FixItOS(FixItString);
- FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available"
- : "__builtin_available")
- << "("
- << AvailabilityAttr::getPlatformNameSourceSpelling(
- SemaRef.getASTContext().getTargetInfo().getPlatformName())
- << " " << Introduced.getAsString() << ", *)) {\n"
- << Indentation << ExtraIndentation;
- FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str());
- SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken(
- StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(),
- /*SkipTrailingWhitespaceAndNewLine=*/false);
- if (ElseInsertionLoc.isInvalid())
- ElseInsertionLoc =
- Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts());
- FixItOS.str().clear();
- FixItOS << "\n"
- << Indentation << "} else {\n"
- << Indentation << ExtraIndentation
- << "// Fallback on earlier versions\n"
- << Indentation << "}";
- FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str());
- }
- }
- bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) {
- const Type *TyPtr = Ty.getTypePtr();
- SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()};
- if (Range.isInvalid())
- return true;
- if (const auto *TT = dyn_cast<TagType>(TyPtr)) {
- TagDecl *TD = TT->getDecl();
- DiagnoseDeclAvailability(TD, Range);
- } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) {
- TypedefNameDecl *D = TD->getDecl();
- DiagnoseDeclAvailability(D, Range);
- } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) {
- if (NamedDecl *D = ObjCO->getInterface())
- DiagnoseDeclAvailability(D, Range);
- }
- return true;
- }
- bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) {
- VersionTuple CondVersion;
- if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) {
- CondVersion = E->getVersion();
- // If we're using the '*' case here or if this check is redundant, then we
- // use the enclosing version to check both branches.
- if (CondVersion.empty() || CondVersion <= AvailabilityStack.back())
- return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse());
- } else {
- // This isn't an availability checking 'if', we can just continue.
- return Base::TraverseIfStmt(If);
- }
- AvailabilityStack.push_back(CondVersion);
- bool ShouldContinue = TraverseStmt(If->getThen());
- AvailabilityStack.pop_back();
- return ShouldContinue && TraverseStmt(If->getElse());
- }
- } // end anonymous namespace
- void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
- Stmt *Body = nullptr;
- if (auto *FD = D->getAsFunction()) {
- // FIXME: We only examine the pattern decl for availability violations now,
- // but we should also examine instantiated templates.
- if (FD->isTemplateInstantiation())
- return;
- Body = FD->getBody();
- } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D))
- Body = MD->getBody();
- else if (auto *BD = dyn_cast<BlockDecl>(D))
- Body = BD->getBody();
- assert(Body && "Need a body here!");
- DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body);
- }
- void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D,
- ArrayRef<SourceLocation> Locs,
- const ObjCInterfaceDecl *UnknownObjCClass,
- bool ObjCPropertyAccess,
- bool AvoidPartialAvailabilityChecks,
- ObjCInterfaceDecl *ClassReceiver) {
- std::string Message;
- AvailabilityResult Result;
- const NamedDecl* OffendingDecl;
- // See if this declaration is unavailable, deprecated, or partial.
- std::tie(Result, OffendingDecl) =
- ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver);
- if (Result == AR_Available)
- return;
- if (Result == AR_NotYetIntroduced) {
- if (AvoidPartialAvailabilityChecks)
- return;
- // We need to know the @available context in the current function to
- // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that
- // when we're done parsing the current function.
- if (getCurFunctionOrMethodDecl()) {
- getEnclosingFunction()->HasPotentialAvailabilityViolations = true;
- return;
- } else if (getCurBlock() || getCurLambda()) {
- getCurFunction()->HasPotentialAvailabilityViolations = true;
- return;
- }
- }
- const ObjCPropertyDecl *ObjCPDecl = nullptr;
- if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
- AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
- if (PDeclResult == Result)
- ObjCPDecl = PD;
- }
- }
- EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs,
- UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess);
- }
|