Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -386,6 +386,7 @@ bool isTriviallyRecursive(const FunctionDecl *F); bool shouldEmitFunction(GlobalDecl GD); + bool shouldEmitGlobalVariable(const VarDecl *D); /// @name Cache for Blocks Runtime Globals /// @{ Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1240,6 +1240,13 @@ return !isTriviallyRecursive(F); } +bool CodeGenModule::shouldEmitGlobalVariable(const VarDecl *VD) { + if (GetLLVMLinkageVarDefinition(VD, /*isConstant=*/true) != + llvm::Function::AvailableExternallyLinkage) + return true; + return CodeGenOpts.OptimizationLevel != 0; +} + /// If the type for the method's class was generated by /// CGDebugInfo::createContextChain(), the cache contains only a /// limited DIType without any declarations. Since EmitFunctionStart() @@ -1290,8 +1297,13 @@ return EmitGlobalFunctionDefinition(GD); } - if (const VarDecl *VD = dyn_cast(D)) + if (const VarDecl *VD = dyn_cast(D)) { + // At -O0, don't generate IR for vars with available_externally linkage. + if (!shouldEmitGlobalVariable(VD)) + return; + return EmitGlobalVarDefinition(VD); + } llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } @@ -1534,6 +1546,16 @@ CXXThreadLocals.push_back(std::make_pair(D, GV)); setTLSMode(GV, *D); } + + // If the variable has an initializer but no definition we can emit it with + // available_externally linkage. + if (D->hasInit() && !D->hasDefinition(Context)) { + assert(!D->getType().isVolatileQualified()); + assert(GetLLVMLinkageVarDefinition(D, /*isConstant=*/true) == + llvm::GlobalValue::AvailableExternallyLinkage && + "Global variable should be available_externally!"); + DeferredDeclsToEmit.push_back(D); + } } if (AddrSpace != Ty->getAddressSpace()) @@ -1816,6 +1838,14 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) { + // Check for definitionless vars. We can emit them with available_externally + // linkage. + if (D->hasInit() && !D->hasDefinition(Context)) { + assert(isTypeConstant(D->getType(), /*ExcludeCtor=*/true) && + "Variable with init but no definition should be constant!"); + return llvm::GlobalValue::AvailableExternallyLinkage; + } + GVALinkage Linkage = getContext().GetGVALinkageForVariable(D); if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; Index: test/CodeGenCXX/constexpr-available-externally.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/constexpr-available-externally.cpp @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -emit-llvm -O1 -std=c++11 -disable-llvm-optzns -o - %s | FileCheck %s + +// PR17612 +// CHECK: @_ZN6Object3fooE = available_externally constant %struct.Literal { i32 1 } +// CHECK: @_ZN6Object3barE = available_externally constant i32 42 + +struct Literal { + int i; + constexpr Literal(int i) : i(i) {} +}; + +struct Object { + static constexpr Literal foo = Literal(1); + static const int bar = 42; +}; + +void bar(const int &); + +int f() { + Literal l = Object::foo; + bar(Object::bar); + return l.i; + +// CHECK-LABEL: @_Z1fv +// CHECK: call void @llvm.memcpy{{[^(]*}}(i8* %{{[^,]*}}, i8* bitcast (%struct.Literal* @_ZN6Object3fooE to i8*) +// CHECK: call void @_Z3barRKi(i32* @_ZN6Object3barE) +}