Author: dpolukhin Date: Mon Apr 11 02:48:59 2016 New Revision: 265917 URL: http://llvm.org/viewvc/llvm-project?rev=265917&view=rev Log: [GCC] Attribute ifunc support in clang
This patch add support for GCC attribute((ifunc("resolver"))) for targets that use ELF as object file format. In general ifunc is a special kind of function alias with type @gnu_indirect_function. LLVM patch http://reviews.llvm.org/D15525 Differential Revision: http://reviews.llvm.org/D15524 Added: cfe/trunk/test/CodeGen/ifunc.c (with props) cfe/trunk/test/Sema/attr-ifunc.c (with props) Modified: cfe/trunk/include/clang/AST/DeclBase.h cfe/trunk/include/clang/Basic/Attr.td cfe/trunk/include/clang/Basic/AttrDocs.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/AST/Decl.cpp cfe/trunk/lib/AST/DeclBase.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/CodeGen/CodeGenModule.h cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/test/Sema/attr-alias-elf.c Modified: cfe/trunk/include/clang/AST/DeclBase.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclBase.h (original) +++ cfe/trunk/include/clang/AST/DeclBase.h Mon Apr 11 02:48:59 2016 @@ -567,6 +567,13 @@ public: return NextInContextAndBits.getInt() & ModulePrivateFlag; } + /// Return true if this declaration has an attribute which acts as + /// definition of the entity, such as 'alias' or 'ifunc'. + bool hasDefiningAttr() const; + + /// Return this declaration's defining attribute if it has one. + const Attr *getDefiningAttr() const; + protected: /// \brief Specify whether this declaration was marked as being private /// to the module in which it was defined. Modified: cfe/trunk/include/clang/Basic/Attr.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/Attr.td (original) +++ cfe/trunk/include/clang/Basic/Attr.td Mon Apr 11 02:48:59 2016 @@ -855,6 +855,13 @@ def IBOutletCollection : InheritableAttr let Documentation = [Undocumented]; } +def IFunc : Attr { + let Spellings = [GCC<"ifunc">]; + let Args = [StringArgument<"Resolver">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [IFuncDocs]; +} + def Restrict : InheritableAttr { let Spellings = [Declspec<"restrict">, GCC<"malloc">]; let Subjects = SubjectList<[Function]>; Modified: cfe/trunk/include/clang/Basic/AttrDocs.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/AttrDocs.td?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/AttrDocs.td (original) +++ cfe/trunk/include/clang/Basic/AttrDocs.td Mon Apr 11 02:48:59 2016 @@ -2358,3 +2358,16 @@ to replace the deprecated name with a ne string argument which is the message to display when emitting the warning. }]; } + +def IFuncDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +``__attribute__((ifunc("resolver")))`` is used to mark that the address of a declaration should be resolved at runtime by calling a resolver function. + +The symbol name of the resolver function is given in quotes. A function with this name (after mangling) must be defined in the current translation unit; it may be ``static``. The resolver function should take no arguments and return a pointer. + +The ``ifunc`` attribute may only be used on a function declaration. A function declaration with an ``ifunc`` attribute is considered to be a definition of the declared entity. The entity must not have weak linkage; for example, in C++, it cannot be applied to a declaration if a definition at that location would be considered inline. + +Not all targets support this attribute. ELF targets support this attribute when using binutils v2.20.1 or higher and glibc v2.11.1 or higher. Non-ELF targets currently do not support this attribute. + }]; +} Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Apr 11 02:48:59 2016 @@ -2464,17 +2464,21 @@ def err_attribute_weakref_without_alias def err_alias_not_supported_on_darwin : Error < "only weak aliases are supported on darwin">; def err_alias_to_undefined : Error< - "alias must point to a defined variable or function">; + "%select{alias|ifunc}0 must point to a defined %select{variable or |}1function">; def warn_alias_to_weak_alias : Warning< - "alias will always resolve to %0 even if weak definition of alias %1 is overridden">, + "%select{alias|ifunc}2 will always resolve to %0 even if weak definition of %1 is overridden">, InGroup<IgnoredAttributes>; def warn_alias_with_section : Warning< - "alias will not be in section '%0' but in the same section as the aliasee">, + "%select{alias|ifunc}1 will not be in section '%0' but in the same section as the %select{aliasee|resolver}2">, InGroup<IgnoredAttributes>; def err_duplicate_mangled_name : Error< "definition with same mangled name as another definition">; def err_cyclic_alias : Error< - "alias definition is part of a cycle">; + "%select{alias|ifunc}0 definition is part of a cycle">; +def err_ifunc_resolver_return : Error< + "ifunc resolver function must return a pointer">; +def err_ifunc_resolver_params : Error< + "ifunc resolver function must have no parameters">; def warn_attribute_wrong_decl_type : Warning< "%0 attribute only applies to %select{functions|unions|" "variables and functions|functions and methods|parameters|" @@ -4196,7 +4200,7 @@ def err_redefinition : Error<"redefiniti def err_alias_after_tentative : Error<"alias definition of %0 after tentative definition">; def err_alias_is_definition : - Error<"definition %0 cannot also be an alias">; + Error<"definition %0 cannot also be an %select{alias|ifunc}1">; def err_definition_of_implicitly_declared_member : Error< "definition of implicitly declared %select{default constructor|copy " "constructor|move constructor|copy assignment operator|move assignment " Modified: cfe/trunk/lib/AST/Decl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/lib/AST/Decl.cpp (original) +++ cfe/trunk/lib/AST/Decl.cpp Mon Apr 11 02:48:59 2016 @@ -1946,7 +1946,7 @@ VarDecl::isThisDeclarationADefinition(AS if (hasInit()) return Definition; - if (hasAttr<AliasAttr>()) + if (hasDefiningAttr()) return Definition; if (const auto *SAA = getAttr<SelectAnyAttr>()) @@ -2486,7 +2486,7 @@ bool FunctionDecl::hasTrivialBody() cons bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { for (auto I : redecls()) { if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed || - I->hasAttr<AliasAttr>()) { + I->hasDefiningAttr()) { Definition = I->IsDeleted ? I->getCanonicalDecl() : I; return true; } Modified: cfe/trunk/lib/AST/DeclBase.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp (original) +++ cfe/trunk/lib/AST/DeclBase.cpp Mon Apr 11 02:48:59 2016 @@ -362,6 +362,18 @@ bool Decl::isReferenced() const { return false; } +bool Decl::hasDefiningAttr() const { + return hasAttr<AliasAttr>() || hasAttr<IFuncAttr>(); +} + +const Attr *Decl::getDefiningAttr() const { + if (AliasAttr *AA = getAttr<AliasAttr>()) + return AA; + if (IFuncAttr *IFA = getAttr<IFuncAttr>()) + return IFA; + return nullptr; +} + /// \brief Determine the availability of the given declaration based on /// the target platform. /// Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Mon Apr 11 02:48:59 2016 @@ -274,20 +274,21 @@ void CodeGenModule::applyGlobalValReplac // This is only used in aliases that we created and we know they have a // linear structure. -static const llvm::GlobalObject *getAliasedGlobal(const llvm::GlobalAlias &GA) { - llvm::SmallPtrSet<const llvm::GlobalAlias*, 4> Visited; - const llvm::Constant *C = &GA; +static const llvm::GlobalObject *getAliasedGlobal( + const llvm::GlobalIndirectSymbol &GIS) { + llvm::SmallPtrSet<const llvm::GlobalIndirectSymbol*, 4> Visited; + const llvm::Constant *C = &GIS; for (;;) { C = C->stripPointerCasts(); if (auto *GO = dyn_cast<llvm::GlobalObject>(C)) return GO; // stripPointerCasts will not walk over weak aliases. - auto *GA2 = dyn_cast<llvm::GlobalAlias>(C); - if (!GA2) + auto *GIS2 = dyn_cast<llvm::GlobalIndirectSymbol>(C); + if (!GIS2) return nullptr; - if (!Visited.insert(GA2).second) + if (!Visited.insert(GIS2).second) return nullptr; - C = GA2->getAliasee(); + C = GIS2->getIndirectSymbol(); } } @@ -299,20 +300,35 @@ void CodeGenModule::checkAliases() { DiagnosticsEngine &Diags = getDiags(); for (const GlobalDecl &GD : Aliases) { const auto *D = cast<ValueDecl>(GD.getDecl()); - const AliasAttr *AA = D->getAttr<AliasAttr>(); + SourceLocation Location; + bool IsIFunc = D->hasAttr<IFuncAttr>(); + if (const Attr *A = D->getDefiningAttr()) + Location = A->getLocation(); + else + llvm_unreachable("Not an alias or ifunc?"); StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); - auto *Alias = cast<llvm::GlobalAlias>(Entry); + auto *Alias = cast<llvm::GlobalIndirectSymbol>(Entry); const llvm::GlobalValue *GV = getAliasedGlobal(*Alias); if (!GV) { Error = true; - Diags.Report(AA->getLocation(), diag::err_cyclic_alias); + Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc; } else if (GV->isDeclaration()) { Error = true; - Diags.Report(AA->getLocation(), diag::err_alias_to_undefined); + Diags.Report(Location, diag::err_alias_to_undefined) + << IsIFunc << IsIFunc; + } else if (IsIFunc) { + // Check resolver function type. + llvm::FunctionType *FTy = dyn_cast<llvm::FunctionType>( + GV->getType()->getPointerElementType()); + assert(FTy); + if (!FTy->getReturnType()->isPointerTy()) + Diags.Report(Location, diag::err_ifunc_resolver_return); + if (FTy->getNumParams()) + Diags.Report(Location, diag::err_ifunc_resolver_params); } - llvm::Constant *Aliasee = Alias->getAliasee(); + llvm::Constant *Aliasee = Alias->getIndirectSymbol(); llvm::GlobalValue *AliaseeGV; if (auto CE = dyn_cast<llvm::ConstantExpr>(Aliasee)) AliaseeGV = cast<llvm::GlobalValue>(CE->getOperand(0)); @@ -323,7 +339,7 @@ void CodeGenModule::checkAliases() { StringRef AliasSection = SA->getName(); if (AliasSection != AliaseeGV->getSection()) Diags.Report(SA->getLocation(), diag::warn_alias_with_section) - << AliasSection; + << AliasSection << IsIFunc << IsIFunc; } // We have to handle alias to weak aliases in here. LLVM itself disallows @@ -331,13 +347,13 @@ void CodeGenModule::checkAliases() { // compatibility with gcc we implement it by just pointing the alias // to its aliasee's aliasee. We also warn, since the user is probably // expecting the link to be weak. - if (auto GA = dyn_cast<llvm::GlobalAlias>(AliaseeGV)) { + if (auto GA = dyn_cast<llvm::GlobalIndirectSymbol>(AliaseeGV)) { if (GA->isInterposable()) { - Diags.Report(AA->getLocation(), diag::warn_alias_to_weak_alias) - << GV->getName() << GA->getName(); + Diags.Report(Location, diag::warn_alias_to_weak_alias) + << GV->getName() << GA->getName() << IsIFunc; Aliasee = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( - GA->getAliasee(), Alias->getType()); - Alias->setAliasee(Aliasee); + GA->getIndirectSymbol(), Alias->getType()); + Alias->setIndirectSymbol(Aliasee); } } } @@ -347,7 +363,7 @@ void CodeGenModule::checkAliases() { for (const GlobalDecl &GD : Aliases) { StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); - auto *Alias = cast<llvm::GlobalAlias>(Entry); + auto *Alias = dyn_cast<llvm::GlobalIndirectSymbol>(Entry); Alias->replaceAllUsesWith(llvm::UndefValue::get(Alias->getType())); Alias->eraseFromParent(); } @@ -1538,6 +1554,10 @@ void CodeGenModule::EmitGlobal(GlobalDec if (Global->hasAttr<AliasAttr>()) return EmitAliasDefinition(GD); + // IFunc like an alias whose value is resolved at runtime by calling resolver. + if (Global->hasAttr<IFuncAttr>()) + return emitIFuncDefinition(GD); + // If this is CUDA, be selective about which declarations we emit. if (LangOpts.CUDA) { if (LangOpts.CUDAIsDevice) { @@ -2901,7 +2921,7 @@ void CodeGenModule::EmitAliasDefinition( StringRef MangledName = getMangledName(GD); if (AA->getAliasee() == MangledName) { - Diags.Report(AA->getLocation(), diag::err_cyclic_alias); + Diags.Report(AA->getLocation(), diag::err_cyclic_alias) << 0; return; } @@ -2932,7 +2952,7 @@ void CodeGenModule::EmitAliasDefinition( if (Entry) { if (GA->getAliasee() == Entry) { - Diags.Report(AA->getLocation(), diag::err_cyclic_alias); + Diags.Report(AA->getLocation(), diag::err_cyclic_alias) << 0; return; } @@ -2969,6 +2989,65 @@ void CodeGenModule::EmitAliasDefinition( setAliasAttributes(D, GA); } +void CodeGenModule::emitIFuncDefinition(GlobalDecl GD) { + const auto *D = cast<ValueDecl>(GD.getDecl()); + const IFuncAttr *IFA = D->getAttr<IFuncAttr>(); + assert(IFA && "Not an ifunc?"); + + StringRef MangledName = getMangledName(GD); + + if (IFA->getResolver() == MangledName) { + Diags.Report(IFA->getLocation(), diag::err_cyclic_alias) << 1; + return; + } + + // Report an error if some definition overrides ifunc. + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); + if (Entry && !Entry->isDeclaration()) { + GlobalDecl OtherGD; + if (lookupRepresentativeDecl(MangledName, OtherGD) && + DiagnosedConflictingDefinitions.insert(GD).second) { + Diags.Report(D->getLocation(), diag::err_duplicate_mangled_name); + Diags.Report(OtherGD.getDecl()->getLocation(), + diag::note_previous_definition); + } + return; + } + + Aliases.push_back(GD); + + llvm::Type *DeclTy = getTypes().ConvertTypeForMem(D->getType()); + llvm::Constant *Resolver = + GetOrCreateLLVMFunction(IFA->getResolver(), DeclTy, GD, + /*ForVTable=*/false); + llvm::GlobalIFunc *GIF = + llvm::GlobalIFunc::create(DeclTy, 0, llvm::Function::ExternalLinkage, + "", Resolver, &getModule()); + if (Entry) { + if (GIF->getResolver() == Entry) { + Diags.Report(IFA->getLocation(), diag::err_cyclic_alias) << 1; + return; + } + assert(Entry->isDeclaration()); + + // If there is a declaration in the module, then we had an extern followed + // by the ifunc, as in: + // extern int test(); + // ... + // int test() __attribute__((ifunc("resolver"))); + // + // Remove it and replace uses of it with the ifunc. + GIF->takeName(Entry); + + Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GIF, + Entry->getType())); + Entry->eraseFromParent(); + } else + GIF->setName(MangledName); + + SetCommonAttributes(D, GIF); +} + llvm::Function *CodeGenModule::getIntrinsic(unsigned IID, ArrayRef<llvm::Type*> Tys) { return llvm::Intrinsic::getDeclaration(&getModule(), (llvm::Intrinsic::ID)IID, Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Mon Apr 11 02:48:59 2016 @@ -1175,6 +1175,7 @@ private: void EmitGlobalFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false); void EmitAliasDefinition(GlobalDecl GD); + void emitIFuncDefinition(GlobalDecl GD); void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D); void EmitObjCIvarInitializations(ObjCImplementationDecl *D); Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Apr 11 02:48:59 2016 @@ -2299,7 +2299,7 @@ static void checkNewAttributesAfterDef(S for (unsigned I = 0, E = NewAttributes.size(); I != E;) { const Attr *NewAttribute = NewAttributes[I]; - if (isa<AliasAttr>(NewAttribute)) { + if (isa<AliasAttr>(NewAttribute) || isa<IFuncAttr>(NewAttribute)) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) { Sema::SkipBodyInfo SkipBody; S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def), &SkipBody); @@ -5464,7 +5464,7 @@ static void checkAttributesAfterMerging( if (const auto *Attr = VD->getAttr<AliasAttr>()) { assert(VD->isThisDeclarationADefinition() && !VD->isExternallyVisible() && "Broken AliasAttr handled late!"); - S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD; + S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD << 0; VD->dropAttr<AliasAttr>(); } } Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Apr 11 02:48:59 2016 @@ -1548,6 +1548,28 @@ static void handleWeakRefAttr(Sema &S, D Attr.getAttributeSpellingListIndex())); } +static void handleIFuncAttr(Sema &S, Decl *D, const AttributeList &Attr) { + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + return; + + // Aliases should be on declarations, not definitions. + const auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1; + return; + } + // FIXME: it should be handled as a target specific attribute. + if (S.Context.getTargetInfo().getTriple().getObjectFormat() != + llvm::Triple::ELF) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + return; + } + + D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str, + Attr.getAttributeSpellingListIndex())); +} + static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef Str; if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) @@ -1564,13 +1586,13 @@ static void handleAliasAttr(Sema &S, Dec // Aliases should be on declarations, not definitions. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD; + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0; return; } } else { const auto *VD = cast<VarDecl>(D); if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD; + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD << 0; return; } } @@ -5373,6 +5395,9 @@ static void ProcessDeclAttribute(Sema &S case AttributeList::AT_IBOutletCollection: handleIBOutletCollection(S, D, Attr); break; + case AttributeList::AT_IFunc: + handleIFuncAttr(S, D, Attr); + break; case AttributeList::AT_Alias: handleAliasAttr(S, D, Attr); break; Added: cfe/trunk/test/CodeGen/ifunc.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/ifunc.c?rev=265917&view=auto ============================================================================== --- cfe/trunk/test/CodeGen/ifunc.c (added) +++ cfe/trunk/test/CodeGen/ifunc.c Mon Apr 11 02:48:59 2016 @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple i386-unknown-linux-gnu -O2 -emit-llvm -o - %s | FileCheck %s + +int foo(int) __attribute__ ((ifunc("foo_ifunc"))); + +static int f1(int i) { + return i + 1; +} + +static int f2(int i) { + return i + 2; +} + +typedef int (*foo_t)(int); + +int global; + +static foo_t foo_ifunc() { + return global ? f1 : f2; +} + +int bar() { + return foo(1); +} + +extern void goo(void); + +void bar2(void) { + goo(); +} + +extern void goo(void) __attribute__ ((ifunc("goo_ifunc"))); + +void* goo_ifunc(void) { + return 0; +} +// CHECK: @foo = ifunc i32 (i32), bitcast (i32 (i32)* ()* @foo_ifunc to i32 (i32)*) +// CHECK: @goo = ifunc void (), bitcast (i8* ()* @goo_ifunc to void ()*) + +// CHECK: call i32 @foo(i32 +// CHECK: call void @goo() Propchange: cfe/trunk/test/CodeGen/ifunc.c ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/CodeGen/ifunc.c ------------------------------------------------------------------------------ svn:keywords = "Author Date Id Rev URL" Propchange: cfe/trunk/test/CodeGen/ifunc.c ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: cfe/trunk/test/Sema/attr-alias-elf.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-alias-elf.c?rev=265917&r1=265916&r2=265917&view=diff ============================================================================== --- cfe/trunk/test/Sema/attr-alias-elf.c (original) +++ cfe/trunk/test/Sema/attr-alias-elf.c Mon Apr 11 02:48:59 2016 @@ -55,7 +55,7 @@ typedef int b4; void test2_bar() {} void test2_foo() __attribute__((weak, alias("test2_bar"))); -void test2_zed() __attribute__((alias("test2_foo"))); // expected-warning {{alias will always resolve to test2_bar even if weak definition of alias test2_foo is overridden}} +void test2_zed() __attribute__((alias("test2_foo"))); // expected-warning {{alias will always resolve to test2_bar even if weak definition of test2_foo is overridden}} void test3_bar() { } void test3_foo() __attribute__((section("test"))); // expected-warning {{alias will not be in section 'test' but in the same section as the aliasee}} Added: cfe/trunk/test/Sema/attr-ifunc.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-ifunc.c?rev=265917&view=auto ============================================================================== --- cfe/trunk/test/Sema/attr-ifunc.c (added) +++ cfe/trunk/test/Sema/attr-ifunc.c Mon Apr 11 02:48:59 2016 @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -triple x86_64-windows -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm -DCHECK_ALIASES %s +// RUN: %clang_cc1 -triple x86_64-linux -fsyntax-only -verify -emit-llvm %s + +#if defined(_WIN32) +void foo() {} +void bar() __attribute__((ifunc("foo"))); +//expected-warning@-1 {{'ifunc' attribute ignored}} + +#else +#if defined(CHECK_ALIASES) +void* f1_ifunc(); +void f1() __attribute__((ifunc("f1_ifunc"))); +//expected-error@-1 {{ifunc must point to a defined function}} + +void* f2_a() __attribute__((ifunc("f2_b"))); +//expected-error@-1 {{ifunc definition is part of a cycle}} +void* f2_b() __attribute__((ifunc("f2_a"))); +//expected-error@-1 {{ifunc definition is part of a cycle}} + +void* f3_a() __attribute__((ifunc("f3_b"))); +//expected-warning@-1 {{ifunc will always resolve to f3_c even if weak definition of f3_b is overridden}} +void* f3_b() __attribute__((weak, alias("f3_c"))); +void* f3_c() { return 0; } + +void f4_ifunc() {} +void f4() __attribute__((ifunc("f4_ifunc"))); +//expected-error@-1 {{ifunc resolver function must return a pointer}} + +void* f5_ifunc(int i) { return 0; } +void f5() __attribute__((ifunc("f5_ifunc"))); +//expected-error@-1 {{ifunc resolver function must have no parameters}} + +#else +void f1a() __asm("f1"); +void f1a() {} +//expected-note@-1 {{previous definition is here}} +void f1() __attribute__((ifunc("f1_ifunc"))); +//expected-error@-1 {{definition with same mangled name as another definition}} +void* f1_ifunc() { return 0; } + +#endif +#endif Propchange: cfe/trunk/test/Sema/attr-ifunc.c ------------------------------------------------------------------------------ svn:eol-style = native Propchange: cfe/trunk/test/Sema/attr-ifunc.c ------------------------------------------------------------------------------ svn:keywords = "Author Date Id Rev URL" Propchange: cfe/trunk/test/Sema/attr-ifunc.c ------------------------------------------------------------------------------ svn:mime-type = text/plain _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits