// which case the caller is responsible for ensuring the soundness
// of these semantics.
auto *Ref = cast<llvm::GlobalValue>(GetAddrOfGlobal(TargetDecl));
- llvm::Constant *Aliasee = Ref;
- if (Ref->getType() != AliasType)
- Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType);
+ auto *Aliasee = dyn_cast<llvm::GlobalObject>(Ref);
+ if (!Aliasee)
+ Aliasee = cast<llvm::GlobalAlias>(Ref)->getAliasee();
// Instead of creating as alias to a linkonce_odr, replace all of the uses
- // of the aliassee.
+ // of the aliasee.
if (llvm::GlobalValue::isDiscardableIfUnused(Linkage) &&
(TargetLinkage != llvm::GlobalValue::AvailableExternallyLinkage ||
!TargetDecl.getDecl()->hasAttr<AlwaysInlineAttr>())) {
// members with attribute "AlwaysInline" and expect no reference to
// be generated. It is desirable to reenable this optimisation after
// corresponding LLVM changes.
- Replacements[MangledName] = Aliasee;
+ llvm::Constant *Replacement = Aliasee;
+ if (Aliasee->getType() != AliasType)
+ Replacement = llvm::ConstantExpr::getBitCast(Aliasee, AliasType);
+ Replacements[MangledName] = Replacement;
return false;
}
/// If we don't have a definition for the destructor yet, don't
/// emit. We can't emit aliases to declarations; that's just not
/// how aliases work.
- if (Ref->isDeclaration())
+ if (Aliasee->isDeclaration())
return true;
}
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
auto *Alias = cast<llvm::GlobalAlias>(Entry);
llvm::GlobalValue *GV = Alias->getAliasedGlobal();
- if (!GV) {
- Error = true;
- Diags.Report(AA->getLocation(), diag::err_cyclic_alias);
- } else if (GV->isDeclaration()) {
+ if (GV->isDeclaration()) {
Error = true;
Diags.Report(AA->getLocation(), diag::err_alias_to_undefined);
}
- llvm::Constant *Aliasee = Alias->getAliasee();
- llvm::GlobalValue *AliaseeGV;
- if (auto CE = dyn_cast<llvm::ConstantExpr>(Aliasee)) {
- assert((CE->getOpcode() == llvm::Instruction::BitCast ||
- CE->getOpcode() == llvm::Instruction::AddrSpaceCast) &&
- "Unsupported aliasee");
- AliaseeGV = cast<llvm::GlobalValue>(CE->getOperand(0));
- } else {
- AliaseeGV = cast<llvm::GlobalValue>(Aliasee);
- }
-
+ llvm::GlobalObject *Aliasee = Alias->getAliasee();
if (const SectionAttr *SA = D->getAttr<SectionAttr>()) {
StringRef AliasSection = SA->getName();
- if (AliasSection != AliaseeGV->getSection())
+ if (AliasSection != Aliasee->getSection())
Diags.Report(SA->getLocation(), diag::warn_alias_with_section)
<< AliasSection;
}
-
- // We have to handle alias to weak aliases in here. LLVM itself disallows
- // this since the object semantics would not match the IL one. For
- // 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 (GA->mayBeOverridden()) {
- Diags.Report(AA->getLocation(), diag::warn_alias_to_weak_alias)
- << GA->getAliasedGlobal()->getName() << GA->getName();
- Aliasee = llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast(
- GA->getAliasee(), Alias->getType());
- Alias->setAliasee(Aliasee);
- }
- }
}
if (!Error)
return;
AddGlobalAnnotations(D, Fn);
}
+static llvm::GlobalObject &getGlobalObjectInExpr(DiagnosticsEngine &Diags,
+ const AliasAttr *AA,
+ llvm::Constant *C) {
+ if (auto *GO = dyn_cast<llvm::GlobalObject>(C))
+ return *GO;
+
+ auto *GA = dyn_cast<llvm::GlobalAlias>(C);
+ if (GA) {
+ if (GA->mayBeOverridden()) {
+ Diags.Report(AA->getLocation(), diag::warn_alias_to_weak_alias)
+ << GA->getAliasee()->getName() << GA->getName();
+ }
+
+ return *GA->getAliasee();
+ }
+
+ auto *CE = cast<llvm::ConstantExpr>(C);
+ assert(CE->getOpcode() == llvm::Instruction::BitCast ||
+ CE->getOpcode() == llvm::Instruction::GetElementPtr ||
+ CE->getOpcode() == llvm::Instruction::AddrSpaceCast);
+ return *cast<llvm::GlobalObject>(CE->getOperand(0));
+}
+
void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
const auto *D = cast<ValueDecl>(GD.getDecl());
const AliasAttr *AA = D->getAttr<AliasAttr>();
// Create the new alias itself, but don't set a name yet.
auto *GA = new llvm::GlobalAlias(
cast<llvm::PointerType>(Aliasee->getType())->getElementType(),
- llvm::Function::ExternalLinkage, "", Aliasee, &getModule());
+ llvm::Function::ExternalLinkage, "",
+ &getGlobalObjectInExpr(Diags, AA, Aliasee), &getModule());
if (Entry) {
+ if (GA->getAliasee() == Entry) {
+ Diags.Report(AA->getLocation(), diag::err_cyclic_alias);
+ return;
+ }
+
assert(Entry->isDeclaration());
// If there is a declaration in the module, then we had an extern followed
IdentifierInfo *Name = I->first;
llvm::GlobalValue *Val = I->second;
if (Val && !getModule().getNamedValue(Name->getName()))
- addUsedGlobal(new llvm::GlobalAlias(Val->getType()->getElementType(),
- Val->getLinkage(), Name->getName(),
- Val, &getModule()));
+ addUsedGlobal(new llvm::GlobalAlias(
+ Val->getType()->getElementType(), Val->getLinkage(), Name->getName(),
+ cast<llvm::GlobalObject>(Val), &getModule()));
}
}
unsigned Num = attr->getNumber() / 2;
new llvm::GlobalAlias(GV->getType()->getElementType(),
llvm::Function::ExternalLinkage,
- "__isr_" + Twine(Num), GV, &M.getModule());
+ "__isr_" + Twine(Num), F, &M.getModule());
}
}
}
extern void f1(void);
extern void f1(void) __attribute((alias("f0")));
// CHECKBASIC-DAG: @f1 = alias void ()* @f0
-// CHECKBASIC-DAG: @test8_foo = alias weak bitcast (void ()* @test8_bar to void (...)*)
-// CHECKBASIC-DAG: @test8_zed = alias bitcast (void ()* @test8_bar to void (...)*)
+// CHECKBASIC-DAG: @test8_foo = alias weak void (...), void ()* @test8_bar
+// CHECKBASIC-DAG: @test8_zed = alias void (...), void ()* @test8_bar
// CHECKBASIC-DAG: @test9_zed = alias void ()* @test9_bar
// CHECKBASIC: define void @f0() [[NUW:#[0-9]+]] {
// CHECK: @t12 = global i32 0, section "SECT"
int t12 __attribute__((section("SECT")));
-// CHECK: @t9 = alias weak bitcast (void ()* @__t8 to void (...)*)
+// CHECK: @t9 = alias weak void (...), void ()* @__t8
void __t8() {}
void t9() __attribute__((weak, alias("__t8")));
namespace test8 {
// Test that we replace ~zed with ~bar which is an alias to ~foo.
- // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test83barD2Ev
+ // CHECK-DAG: call i32 @__cxa_atexit({{.*}}@_ZN5test83fooD2Ev
// CHECK-DAG: @_ZN5test83barD2Ev = alias {{.*}} @_ZN5test83fooD2Ev
struct foo {
~foo();
// CHECK-DAG: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
// CHECK-DAG: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
// CHECK-DAG: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// CHECK-DAG: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
+// CHECK-DAG: @_ZN5test11SD2Ev = alias {{.*}} @_ZN5test11AD2Ev
// WIN32-DAG: @_ZN5test01AD1Ev = alias {{.*}} @_ZN5test01AD2Ev
// WIN32-DAG: @_ZN5test11MD2Ev = alias {{.*}} @_ZN5test11AD2Ev
// WIN32-DAG: @_ZN5test11ND2Ev = alias {{.*}} @_ZN5test11AD2Ev
// WIN32-DAG: @_ZN5test11OD2Ev = alias {{.*}} @_ZN5test11AD2Ev
-// WIN32-DAG: @_ZN5test11SD2Ev = alias bitcast {{.*}} @_ZN5test11AD2Ev
+// WIN32-DAG: @_ZN5test11SD2Ev = alias {{.*}} @_ZN5test11AD2Ev
struct A {
void foo() {
B b;
}
-// CHECK-DAG: @"\01??1B@test2@@UAE@XZ" = alias bitcast (void (%"struct.test2::A"*)* @"\01??1A@test2@@UAE@XZ" to void (%"struct.test2::B"*)*)
+// CHECK-DAG: @"\01??1B@test2@@UAE@XZ" = alias void (%"struct.test2::B"*), void (%"struct.test2::A"*)* @"\01??1A@test2@@UAE@XZ"
}
// CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev
// (aliases from C)
-// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1CD2Ev
-// CHECK: @_ZN1CD2Ev = alias bitcast {{.*}} @_ZN1BD2Ev
+// CHECK: @_ZN1CD1Ev = alias {{.*}} @_ZN1BD2Ev
+// CHECK: @_ZN1CD2Ev = alias {{.*}} @_ZN1BD2Ev
// Base dtor: actually calls A's base dtor.
// CHECK-LABEL: define void @_ZN1BD2Ev(%struct.B* %this) unnamed_addr
--- /dev/null
+// RUN: %clang_cc1 -triple x86_64-pc-linux -fsyntax-only -verify -emit-llvm-only %s
+
+// FIXME: The attributes use mangled names. Since we only keep a mapping from
+// mangled name to llvm GlobalValue, we don't see the clang level decl for
+// an alias target when constructing the alias. Given that and that alias cycles
+// are not representable in LLVM, we only note the issues when the cycle is
+// first formed.
+
+// FIXME: This error is detected early in CodeGen. Once the first error is
+// found, Diags.hasErrorOccurred() returs true and we stop the codegen of the
+// file. The consequence is that we don't find any subsequent error.
+
+void f1() __attribute__((alias("g1")));
+void g1() __attribute__((alias("f1"))); // expected-error {{alias definition is part of a cycle}}
+
+void h1() __attribute__((alias("g1")));
void f9() __attribute__((alias("g9")));
void g9() {}
-void f10() __attribute__((alias("g10"))); // expected-error {{alias definition is part of a cycle}}
-void g10() __attribute__((alias("f10"))); // expected-error {{alias definition is part of a cycle}}
-
-// FIXME: This could be a bit better, h10 is not part of the cycle, it points
-// to it.
-void h10() __attribute__((alias("g10"))); // expected-error {{alias definition is part of a cycle}}
-
extern int a1 __attribute__((alias("b1")));
int b1 = 42;