diff --git a/llvm/include/llvm/IR/GlobalIFunc.h b/llvm/include/llvm/IR/GlobalIFunc.h --- a/llvm/include/llvm/IR/GlobalIFunc.h +++ b/llvm/include/llvm/IR/GlobalIFunc.h @@ -84,6 +84,11 @@ return FunctionType::get(IFuncValTy->getPointerTo(), false); } + static bool isValidLinkage(LinkageTypes L) { + return isExternalLinkage(L) || isLocalLinkage(L) || isWeakLinkage(L) || + isLinkOnceLinkage(L); + } + // Methods for support type inquiry through isa, cast, and dyn_cast: static bool classof(const Value *V) { return V->getValueID() == Value::GlobalIFuncVal; diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -836,13 +836,19 @@ } void Verifier::visitGlobalIFunc(const GlobalIFunc &GI) { + Assert(GlobalIFunc::isValidLinkage(GI.getLinkage()), + "IFunc should have private, internal, linkonce, weak, linkonce_odr, " + "weak_odr, or external linkage!", + &GI); // Pierce through ConstantExprs and GlobalAliases and check that the resolver - // has a Function + // is a Function definition. const Function *Resolver = GI.getResolverFunction(); Assert(Resolver, "IFunc must have a Function resolver", &GI); + Assert(!Resolver->isDeclarationForLinker(), + "IFunc resolver must be a definition", &GI); // Check that the immediate resolver operand (prior to any bitcasts) has the - // correct type + // correct type. const Type *ResolverTy = GI.getResolver()->getType(); const Type *ResolverFuncTy = GlobalIFunc::getResolverFunctionType(GI.getValueType()); diff --git a/llvm/test/Verifier/ifunc.ll b/llvm/test/Verifier/ifunc.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Verifier/ifunc.ll @@ -0,0 +1,29 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +define void ()* @resolver() { + ret void ()* null +} + +@inval_linkage = extern_weak ifunc void (), void ()* ()* @resolver +; CHECK: IFunc should have {{.*}} linkage! +; CHECK-NEXT: @inval_linkage + +@g = external global i32 +@inval_objtype = ifunc void (), bitcast(i32* @g to void ()* ()*) +; CHECK: IFunc must have a Function resolver + +declare void ()* @resolver_decl() +@inval_resolver_decl = ifunc void (), void ()* ()* @resolver_decl +; CHECK: IFunc resolver must be a definition +; CHECK-NEXT: @inval_resolver_decl + +define available_externally void ()* @resolver_linker_decl() { + ret void ()* null +} +@inval_resolver_decl2 = ifunc void (), void ()* ()* @resolver_linker_decl +; CHECK: IFunc resolver must be a definition +; CHECK-NEXT: @inval_resolver_decl2 + +@inval_resolver_type = ifunc i32 (), void ()* ()* @resolver +; CHECK: IFunc resolver has incorrect type +; CHECK-NEXT: @inval_resolver_type