diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -318,21 +318,58 @@ // This is only used in aliases that we created and we know they have a // linear structure. static const llvm::GlobalValue *getAliasedGlobal(const llvm::GlobalValue *GV) { - llvm::SmallPtrSet Visited; - for (;;) { - if (!GV || !Visited.insert(GV).second) - return nullptr; - - const llvm::Constant *C; - if (auto *GA = dyn_cast(GV)) - C = GA->getAliasee(); - else if (auto *GI = dyn_cast(GV)) - C = GI->getResolver(); - else - return GV; + const llvm::Constant *C; + if (auto *GA = dyn_cast(GV)) + C = GA->getAliasee(); + else if (auto *GI = dyn_cast(GV)) + C = GI->getResolver(); + else + return GV; + + const auto *AliaseeGV = dyn_cast(C->stripPointerCasts()); + if (!AliaseeGV) + return nullptr; + + const llvm::GlobalValue *FinalGV = AliaseeGV->getAliaseeObject(); + if (FinalGV == GV) + return nullptr; + + return FinalGV; +} + +static bool checkAliasedGlobal(DiagnosticsEngine &Diags, + SourceLocation Location, + bool IsIFunc, + const llvm::GlobalValue *Alias, + const llvm::GlobalValue *&GV) { + GV = getAliasedGlobal(Alias); + if (!GV) { + Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc; + return false; + } + + if (GV->isDeclaration()) { + Diags.Report(Location, diag::err_alias_to_undefined) << IsIFunc << IsIFunc; + return false; + } + + if (IsIFunc) { + // Check resolver function type. + const auto *F = dyn_cast(GV); + if (!F) { + Diags.Report(Location, diag::err_alias_to_undefined) + << IsIFunc << IsIFunc; + return false; + } - GV = dyn_cast(C->stripPointerCasts()); + llvm::FunctionType *FTy = F->getFunctionType(); + if (!FTy->getReturnType()->isPointerTy()) { + Diags.Report(Location, diag::err_ifunc_resolver_return); + return false; + } } + + return true; } void CodeGenModule::checkAliases() { @@ -349,23 +386,13 @@ Location = A->getLocation(); else llvm_unreachable("Not an alias or ifunc?"); + StringRef MangledName = getMangledName(GD); llvm::GlobalValue *Alias = GetGlobalValue(MangledName); - const llvm::GlobalValue *GV = getAliasedGlobal(Alias); - if (!GV) { - Error = true; - Diags.Report(Location, diag::err_cyclic_alias) << IsIFunc; - } else if (GV->isDeclaration()) { + const llvm::GlobalValue *GV = nullptr; + if (!checkAliasedGlobal(Diags, Location, IsIFunc, Alias, GV)) { Error = true; - Diags.Report(Location, diag::err_alias_to_undefined) - << IsIFunc << IsIFunc; - } else if (IsIFunc) { - // Check resolver function type. - llvm::FunctionType *FTy = dyn_cast( - GV->getType()->getPointerElementType()); - assert(FTy); - if (!FTy->getReturnType()->isPointerTy()) - Diags.Report(Location, diag::err_ifunc_resolver_return); + continue; } llvm::Constant *Aliasee = diff --git a/clang/test/Sema/attr-ifunc.c b/clang/test/Sema/attr-ifunc.c --- a/clang/test/Sema/attr-ifunc.c +++ b/clang/test/Sema/attr-ifunc.c @@ -13,8 +13,7 @@ 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_a() __attribute__((alias("f2_b"))); void* f2_b() __attribute__((ifunc("f2_a"))); //expected-error@-1 {{ifunc definition is part of a cycle}} @@ -27,6 +26,15 @@ void f4() __attribute__((ifunc("f4_ifunc"))); //expected-error@-1 {{ifunc resolver function must return a pointer}} +int f5_resolver_gvar; +void f5() __attribute__((ifunc("f5_resolver_gvar"))); +// expected-error@-1 {{ifunc must point to a defined function}} + +void *f6_resolver_resolver() { return 0; } +void *f6_resolver() __attribute__((ifunc("f6_resolver_resolver"))); +void f6() __attribute__((ifunc("f6_resolver"))); +// expected-error@-1 {{ifunc must point to a defined function}} + #else void f1a() __asm("f1"); void f1a() {}