From 2710ed8fd997be04ff447b8be2190f8fb34ac22b Mon Sep 17 00:00:00 2001
From: Manman Ren
Date: Sat, 16 Mar 2013 00:11:09 +0000
Subject: Exploit this-return of a callsite in a this-return function.
For constructors/desctructors that return 'this', if there exists a callsite
that returns 'this' and is immediately before the return instruction, make
sure we are using the return value from the callsite.
We don't need to keep 'this' alive through the callsite. It also enables
optimizations in the backend, such as tail call optimization.
rdar://12818789
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177211 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/CodeGen/CGClass.cpp | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
(limited to 'lib/CodeGen/CGClass.cpp')
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 287d164cb9..2ececb0365 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1666,8 +1666,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
}
// Non-trivial constructors are handled in an ABI-specific manner.
- CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
- Delegating, This, ArgBeg, ArgEnd);
+ llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
+ ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
+ CalleeWithThisReturn = Callee;
}
void
@@ -1756,9 +1759,12 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param);
}
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
- CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
- ReturnValueSlot(), DelegateArgs, Ctor);
+ Callee, ReturnValueSlot(), DelegateArgs, Ctor);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
+ CalleeWithThisReturn = Callee;
}
namespace {
@@ -1825,6 +1831,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, getContext().getPointerType(getContext().VoidPtrTy),
0, 0);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
+ CalleeWithThisReturn = Callee;
}
namespace {
--
cgit v1.2.3-70-g09d2
From 7cd84baa533ae337e3eb6b7951d94ce94093d521 Mon Sep 17 00:00:00 2001
From: Manman Ren
Date: Sat, 16 Mar 2013 04:47:38 +0000
Subject: revert r177211 due to its potential issues
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177222 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/CodeGen/CGCXXABI.h | 7 +------
lib/CodeGen/CGCall.cpp | 12 ------------
lib/CodeGen/CGClass.cpp | 17 ++++-------------
lib/CodeGen/CodeGenFunction.cpp | 5 -----
lib/CodeGen/CodeGenFunction.h | 4 ----
lib/CodeGen/ItaniumCXXABI.cpp | 11 +++++------
lib/CodeGen/MicrosoftCXXABI.cpp | 5 ++---
test/CodeGenCXX/arm.cpp | 8 ++++----
8 files changed, 16 insertions(+), 53 deletions(-)
(limited to 'lib/CodeGen/CGClass.cpp')
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index d0384ecc12..cdc87b70e5 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -91,10 +91,6 @@ public:
return *MangleCtx;
}
- /// Returns true if the given instance method is one of the
- /// kinds that the ABI says returns 'this'.
- virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
-
/// Find the LLVM type used to represent the given member pointer
/// type.
virtual llvm::Type *
@@ -213,8 +209,7 @@ public:
/// Emit the ABI-specific prolog for the function.
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
- /// Emit the constructor call. Return the function that is called.
- virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
+ virtual void EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 6438ebf846..9e97bce6c3 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1705,18 +1705,6 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
llvm_unreachable("Invalid ABI kind for return argument");
}
- // If this function returns 'this' and the last instruction is a CallInst
- // that returns 'this', use the return value from the CallInst. We will not
- // need to keep 'this' alive through the callsite. It also enables
- // optimizations in the backend, such as tail call optimization.
- if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
- llvm::BasicBlock *IP = Builder.GetInsertBlock();
- llvm::CallInst *Callsite;
- if (!IP->empty() && (Callsite = dyn_cast(&IP->back())) &&
- Callsite->getCalledFunction() == CalleeWithThisReturn)
- // Create a bitcast of Callsite.
- RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
- }
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 2ececb0365..287d164cb9 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1666,11 +1666,8 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
}
// Non-trivial constructors are handled in an ABI-specific manner.
- llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
- ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
- CalleeWithThisReturn = Callee;
+ CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
+ Delegating, This, ArgBeg, ArgEnd);
}
void
@@ -1759,12 +1756,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param);
}
- llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
- Callee, ReturnValueSlot(), DelegateArgs, Ctor);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
- CalleeWithThisReturn = Callee;
+ CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
+ ReturnValueSlot(), DelegateArgs, Ctor);
}
namespace {
@@ -1831,9 +1825,6 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, getContext().getPointerType(getContext().VoidPtrTy),
0, 0);
- if (CGM.getCXXABI().HasThisReturn(CurGD) &&
- CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
- CalleeWithThisReturn = Callee;
}
namespace {
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 98a63464f9..27ef65fa94 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -564,9 +564,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
- // Reset CalleeWithThisReturn.
- CalleeWithThisReturn = 0;
-
// Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
@@ -618,8 +615,6 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());
- // Reset CalleeWithThisReturn.
- CalleeWithThisReturn = 0;
// If we haven't marked the function nothrow through other means, do
// a quick pass now to see if we can.
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 19a4d571ee..55c21e80ee 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1131,10 +1131,6 @@ private:
CGDebugInfo *DebugInfo;
bool DisableDebugInfo;
- /// If the current function returns 'this', use the field to keep track of
- /// the callee that returns 'this'.
- llvm::Value *CalleeWithThisReturn;
-
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
/// calling llvm.stacksave for multiple VLAs in the same scope.
bool DidCallStackSave;
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 17e83a18b9..8c7a759a43 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -112,7 +112,7 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
+ void EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -177,11 +177,11 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
CharUnits cookieSize);
+private:
/// \brief Returns true if the given instance method is one of the
/// kinds that the ARM ABI says returns 'this'.
- bool HasThisReturn(GlobalDecl GD) const {
- const CXXMethodDecl *MD = dyn_cast_or_null(GD.getDecl());
- if (!MD) return false;
+ static bool HasThisReturn(GlobalDecl GD) {
+ const CXXMethodDecl *MD = cast(GD.getDecl());
return ((isa(MD) && GD.getDtorType() != Dtor_Deleting) ||
(isa(MD)));
}
@@ -834,7 +834,7 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
-llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -849,7 +849,6 @@ llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
// FIXME: Provide a source location here.
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, VTTTy, ArgBeg, ArgEnd);
- return Callee;
}
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index 85d926023f..fb6b86d878 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -55,7 +55,7 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
+ void EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -238,7 +238,7 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
}
}
-llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -259,7 +259,6 @@ llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
ImplicitParam, ImplicitParamTy,
ArgBeg, ArgEnd);
- return Callee;
}
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index 48f2f00840..3d3b147aa1 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -56,15 +56,15 @@ namespace test1 {
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
- // CHECK: ret [[A]]* [[THIS2]]
+ // CHECK: call [[A]]* @_ZN5test11AC2Ei(
+ // CHECK: ret [[A]]* [[THIS1]]
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
- // CHECK: ret [[A]]* [[THIS2]]
+ // CHECK: call [[A]]* @_ZN5test11AD2Ev(
+ // CHECK: ret [[A]]* [[THIS1]]
}
// Awkward virtual cases.
--
cgit v1.2.3-70-g09d2
From 63fd408a61ae9b94e8d8a986832f526f7cdbfa84 Mon Sep 17 00:00:00 2001
From: Manman Ren
Date: Wed, 20 Mar 2013 16:59:38 +0000
Subject: Exploit this-return of a callsite in a this-return function.
For constructors/desctructors that return 'this', if there exists a callsite
that returns 'this' and is immediately before the return instruction, make
sure we are using the return value from the callsite.
We don't need to keep 'this' alive through the callsite. It also enables
optimizations in the backend, such as tail call optimization.
Updated from r177211.
rdar://12818789
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@177541 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/CodeGen/CGCXXABI.h | 7 ++-
lib/CodeGen/CGCall.cpp | 25 +++++++++
lib/CodeGen/CGClass.cpp | 17 ++++--
lib/CodeGen/CodeGenFunction.cpp | 7 +++
lib/CodeGen/CodeGenFunction.h | 4 ++
lib/CodeGen/ItaniumCXXABI.cpp | 11 ++--
lib/CodeGen/MicrosoftCXXABI.cpp | 5 +-
test/CodeGenCXX/arm.cpp | 8 +--
.../constructor-destructor-return-this.cpp | 60 ++++++++++++++++++++++
9 files changed, 128 insertions(+), 16 deletions(-)
create mode 100644 test/CodeGenCXX/constructor-destructor-return-this.cpp
(limited to 'lib/CodeGen/CGClass.cpp')
diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h
index cdc87b70e5..d0384ecc12 100644
--- a/lib/CodeGen/CGCXXABI.h
+++ b/lib/CodeGen/CGCXXABI.h
@@ -91,6 +91,10 @@ public:
return *MangleCtx;
}
+ /// Returns true if the given instance method is one of the
+ /// kinds that the ABI says returns 'this'.
+ virtual bool HasThisReturn(GlobalDecl GD) const { return false; }
+
/// Find the LLVM type used to represent the given member pointer
/// type.
virtual llvm::Type *
@@ -209,7 +213,8 @@ public:
/// Emit the ABI-specific prolog for the function.
virtual void EmitInstanceFunctionProlog(CodeGenFunction &CGF) = 0;
- virtual void EmitConstructorCall(CodeGenFunction &CGF,
+ /// Emit the constructor call. Return the function that is called.
+ virtual llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 9e97bce6c3..9318973e64 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1614,6 +1614,18 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
return store;
}
+/// Check whether 'this' argument of a callsite matches 'this' of the caller.
+static bool checkThisPointer(llvm::Value *ThisArg, llvm::Value *This) {
+ if (ThisArg == This)
+ return true;
+ // Check whether ThisArg is a bitcast of This.
+ llvm::BitCastInst *Bitcast;
+ if ((Bitcast = dyn_cast(ThisArg)) &&
+ Bitcast->getOperand(0) == This)
+ return true;
+ return false;
+}
+
void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
// Functions with no result always return void.
if (ReturnValue == 0) {
@@ -1705,6 +1717,19 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI) {
llvm_unreachable("Invalid ABI kind for return argument");
}
+ // If this function returns 'this', the last instruction is a CallInst
+ // that returns 'this', and 'this' argument of the CallInst points to
+ // the same object as CXXThisValue, use the return value from the CallInst.
+ // We will not need to keep 'this' alive through the callsite. It also enables
+ // optimizations in the backend, such as tail call optimization.
+ if (CalleeWithThisReturn && CGM.getCXXABI().HasThisReturn(CurGD)) {
+ llvm::BasicBlock *IP = Builder.GetInsertBlock();
+ llvm::CallInst *Callsite;
+ if (!IP->empty() && (Callsite = dyn_cast(&IP->back())) &&
+ Callsite->getCalledFunction() == CalleeWithThisReturn &&
+ checkThisPointer(Callsite->getOperand(0), CXXThisValue))
+ RV = Builder.CreateBitCast(Callsite, RetAI.getCoerceToType());
+ }
llvm::Instruction *Ret = RV ? Builder.CreateRet(RV) : Builder.CreateRetVoid();
if (!RetDbgLoc.isUnknown())
Ret->setDebugLoc(RetDbgLoc);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 287d164cb9..2ececb0365 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1666,8 +1666,11 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D,
}
// Non-trivial constructors are handled in an ABI-specific manner.
- CGM.getCXXABI().EmitConstructorCall(*this, D, Type, ForVirtualBase,
- Delegating, This, ArgBeg, ArgEnd);
+ llvm::Value *Callee = CGM.getCXXABI().EmitConstructorCall(*this, D, Type,
+ ForVirtualBase, Delegating, This, ArgBeg, ArgEnd);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(D, Type)))
+ CalleeWithThisReturn = Callee;
}
void
@@ -1756,9 +1759,12 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
EmitDelegateCallArg(DelegateArgs, param);
}
+ llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(Ctor, CtorType);
EmitCall(CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, CtorType),
- CGM.GetAddrOfCXXConstructor(Ctor, CtorType),
- ReturnValueSlot(), DelegateArgs, Ctor);
+ Callee, ReturnValueSlot(), DelegateArgs, Ctor);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(Ctor, CtorType)))
+ CalleeWithThisReturn = Callee;
}
namespace {
@@ -1825,6 +1831,9 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD,
EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, getContext().getPointerType(getContext().VoidPtrTy),
0, 0);
+ if (CGM.getCXXABI().HasThisReturn(CurGD) &&
+ CGM.getCXXABI().HasThisReturn(GlobalDecl(DD, Type)))
+ CalleeWithThisReturn = Callee;
}
namespace {
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 27ef65fa94..bd244355f0 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -564,6 +564,10 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
SourceRange BodyRange;
if (Stmt *Body = FD->getBody()) BodyRange = Body->getSourceRange();
+ // CalleeWithThisReturn keeps track of the last callee inside this function
+ // that returns 'this'. Before starting the function, we set it to null.
+ CalleeWithThisReturn = 0;
+
// Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, BodyRange.getBegin());
@@ -615,6 +619,9 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
// Emit the standard function epilogue.
FinishFunction(BodyRange.getEnd());
+ // CalleeWithThisReturn keeps track of the last callee inside this function
+ // that returns 'this'. After finishing the function, we set it to null.
+ CalleeWithThisReturn = 0;
// If we haven't marked the function nothrow through other means, do
// a quick pass now to see if we can.
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 55c21e80ee..19a4d571ee 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1131,6 +1131,10 @@ private:
CGDebugInfo *DebugInfo;
bool DisableDebugInfo;
+ /// If the current function returns 'this', use the field to keep track of
+ /// the callee that returns 'this'.
+ llvm::Value *CalleeWithThisReturn;
+
/// DidCallStackSave - Whether llvm.stacksave has been called. Used to avoid
/// calling llvm.stacksave for multiple VLAs in the same scope.
bool DidCallStackSave;
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 8c7a759a43..17e83a18b9 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -112,7 +112,7 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- void EmitConstructorCall(CodeGenFunction &CGF,
+ llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -177,11 +177,11 @@ public:
llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr,
CharUnits cookieSize);
-private:
/// \brief Returns true if the given instance method is one of the
/// kinds that the ARM ABI says returns 'this'.
- static bool HasThisReturn(GlobalDecl GD) {
- const CXXMethodDecl *MD = cast(GD.getDecl());
+ bool HasThisReturn(GlobalDecl GD) const {
+ const CXXMethodDecl *MD = dyn_cast_or_null(GD.getDecl());
+ if (!MD) return false;
return ((isa(MD) && GD.getDtorType() != Dtor_Deleting) ||
(isa(MD)));
}
@@ -834,7 +834,7 @@ void ARMCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue);
}
-void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+llvm::Value *ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -849,6 +849,7 @@ void ItaniumCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
// FIXME: Provide a source location here.
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
VTT, VTTTy, ArgBeg, ArgEnd);
+ return Callee;
}
RValue ItaniumCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp
index fb6b86d878..85d926023f 100644
--- a/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -55,7 +55,7 @@ public:
void EmitInstanceFunctionProlog(CodeGenFunction &CGF);
- void EmitConstructorCall(CodeGenFunction &CGF,
+ llvm::Value *EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -238,7 +238,7 @@ void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) {
}
}
-void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
+llvm::Value *MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
const CXXConstructorDecl *D,
CXXCtorType Type, bool ForVirtualBase,
bool Delegating,
@@ -259,6 +259,7 @@ void MicrosoftCXXABI::EmitConstructorCall(CodeGenFunction &CGF,
CGF.EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This,
ImplicitParam, ImplicitParamTy,
ArgBeg, ArgEnd);
+ return Callee;
}
RValue MicrosoftCXXABI::EmitVirtualDestructorCall(CodeGenFunction &CGF,
diff --git a/test/CodeGenCXX/arm.cpp b/test/CodeGenCXX/arm.cpp
index 3d3b147aa1..48f2f00840 100644
--- a/test/CodeGenCXX/arm.cpp
+++ b/test/CodeGenCXX/arm.cpp
@@ -56,15 +56,15 @@ namespace test1 {
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: call [[A]]* @_ZN5test11AC2Ei(
- // CHECK: ret [[A]]* [[THIS1]]
+ // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AC2Ei(
+ // CHECK: ret [[A]]* [[THIS2]]
// CHECK: define linkonce_odr [[A]]* @_ZN5test11AD1Ev([[A]]* %this) unnamed_addr
// CHECK: [[THIS:%.*]] = alloca [[A]]*, align 4
// CHECK: store [[A]]* {{.*}}, [[A]]** [[THIS]]
// CHECK: [[THIS1:%.*]] = load [[A]]** [[THIS]]
- // CHECK: call [[A]]* @_ZN5test11AD2Ev(
- // CHECK: ret [[A]]* [[THIS1]]
+ // CHECK: [[THIS2:%.*]] = call [[A]]* @_ZN5test11AD2Ev(
+ // CHECK: ret [[A]]* [[THIS2]]
}
// Awkward virtual cases.
diff --git a/test/CodeGenCXX/constructor-destructor-return-this.cpp b/test/CodeGenCXX/constructor-destructor-return-this.cpp
new file mode 100644
index 0000000000..1ff922de60
--- /dev/null
+++ b/test/CodeGenCXX/constructor-destructor-return-this.cpp
@@ -0,0 +1,60 @@
+//RUN: %clang_cc1 %s -emit-llvm -o - -triple=thumbv7-apple-ios3.0 -target-abi apcs-gnu | FileCheck %s
+
+// For constructors/desctructors that return 'this', if there exists a callsite
+// that returns 'this' and is immediately before the return instruction, make
+// sure we are using the return value from the callsite.
+// rdar://12818789
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN11ObjectCacheC1Ev([[A]] %this) unnamed_addr
+// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN11ObjectCacheC2Ev(
+// CHECK-NEXT: ret [[A]] [[THIS1]]
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheEC1EPS0_MS0_FvPS1_E([[A]] %this
+// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheEC2EPS0_MS0_FvPS1_E(
+// CHECK-NEXT: ret [[A]] [[THIS1]]
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED1Ev([[A]] %this) unnamed_addr
+// CHECK: [[THIS1:%.*]] = call [[A]] @_ZN5TimerI11ObjectCacheED2Ev(
+// CHECK-NEXT: ret [[A]] [[THIS1]]
+
+// CHECK: define linkonce_odr [[A:%.*]] @_ZN5TimerI11ObjectCacheED2Ev([[A]] %this) unnamed_addr
+// CHECK: [[THIS1:%.*]] = call [[B:%.*]] @_ZN9TimerBaseD2Ev(
+// CHECK-NEXT: [[THIS2:%.*]] = bitcast [[B]] [[THIS1]] to [[A]]
+// CHECK-NEXT: ret [[A]] [[THIS2]]
+
+class TimerBase {
+public:
+ TimerBase();
+ virtual ~TimerBase();
+};
+
+template class Timer : public TimerBase {
+public:
+ typedef void (TimerFiredClass::*TimerFiredFunction)(Timer*);
+
+ Timer(TimerFiredClass* o, TimerFiredFunction f)
+ : m_object(o), m_function(f) { }
+
+private:
+ virtual void fired() { (m_object->*m_function)(this); }
+
+ TimerFiredClass* m_object;
+ TimerFiredFunction m_function;
+};
+
+class ObjectCache {
+public:
+ explicit ObjectCache();
+ ~ObjectCache();
+
+private:
+ Timer m_notificationPostTimer;
+};
+
+inline ObjectCache::ObjectCache() : m_notificationPostTimer(this, 0) { }
+inline ObjectCache::~ObjectCache() { }
+
+ObjectCache *test() {
+ ObjectCache *dd = new ObjectCache();
+ return dd;
+}
--
cgit v1.2.3-70-g09d2
From 64aa4b3ec7e62288e2e66c1935487ece995ca94b Mon Sep 17 00:00:00 2001
From: John McCall
Date: Tue, 16 Apr 2013 22:48:15 +0000
Subject: Standardize accesses to the TargetInfo in IR-gen.
Patch by Stephen Lin!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179638 91177308-0d34-0410-b5e6-96231b3b80d8
---
lib/CodeGen/ABIInfo.h | 2 ++
lib/CodeGen/CGAtomic.cpp | 2 +-
lib/CodeGen/CGBlocks.cpp | 3 ++-
lib/CodeGen/CGBuiltin.cpp | 10 ++++----
lib/CodeGen/CGCall.cpp | 9 +++----
lib/CodeGen/CGClass.cpp | 4 +--
lib/CodeGen/CGDebugInfo.cpp | 8 +++---
lib/CodeGen/CGDecl.cpp | 2 +-
lib/CodeGen/CGDeclCXX.cpp | 2 +-
lib/CodeGen/CGExprAgg.cpp | 2 +-
lib/CodeGen/CGExprScalar.cpp | 4 +--
lib/CodeGen/CGObjC.cpp | 2 +-
lib/CodeGen/CGObjCMac.cpp | 18 ++++++-------
lib/CodeGen/CGObjCRuntime.cpp | 2 +-
lib/CodeGen/CGRecordLayoutBuilder.cpp | 8 +++---
lib/CodeGen/CGStmt.cpp | 22 ++++++++--------
lib/CodeGen/CodeGenFunction.cpp | 7 +++--
lib/CodeGen/CodeGenFunction.h | 1 +
lib/CodeGen/CodeGenModule.cpp | 24 +++++++-----------
lib/CodeGen/CodeGenModule.h | 48 ++++++++++++++++++++---------------
lib/CodeGen/CodeGenTypes.cpp | 12 ++++-----
lib/CodeGen/CodeGenTypes.h | 13 ++++++----
lib/CodeGen/ItaniumCXXABI.cpp | 2 +-
lib/CodeGen/TargetInfo.cpp | 39 ++++++++++++++--------------
24 files changed, 126 insertions(+), 120 deletions(-)
(limited to 'lib/CodeGen/CGClass.cpp')
diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h
index 35780f1556..df6dc7216a 100644
--- a/lib/CodeGen/ABIInfo.h
+++ b/lib/CodeGen/ABIInfo.h
@@ -22,6 +22,7 @@ namespace llvm {
namespace clang {
class ASTContext;
+ class TargetInfo;
namespace CodeGen {
class CGFunctionInfo;
@@ -196,6 +197,7 @@ namespace clang {
ASTContext &getContext() const;
llvm::LLVMContext &getVMContext() const;
const llvm::DataLayout &getDataLayout() const;
+ const TargetInfo &getTarget() const;
/// Return the calling convention to use for system runtime
/// functions.
diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp
index 24c930f794..0b48a5c664 100644
--- a/lib/CodeGen/CGAtomic.cpp
+++ b/lib/CodeGen/CGAtomic.cpp
@@ -327,7 +327,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) {
CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy);
unsigned Align = alignChars.getQuantity();
unsigned MaxInlineWidthInBits =
- getContext().getTargetInfo().getMaxAtomicInlineWidth();
+ getTarget().getMaxAtomicInlineWidth();
bool UseLibcall = (Size != Align ||
getContext().toBits(sizeChars) > MaxInlineWidthInBits);
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index ab9793132c..f49198a9bf 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -2082,7 +2082,8 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) {
bool Packed = false;
CharUnits Align = getContext().getDeclAlign(D);
- if (Align > getContext().toCharUnitsFromBits(Target.getPointerAlign(0))) {
+ if (Align >
+ getContext().toCharUnitsFromBits(getTarget().getPointerAlign(0))) {
// We have to insert padding.
// The struct above has 2 32-bit integers.
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 3c89652b6d..37bd8fc1f7 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -296,7 +296,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType);
llvm::Type *ResultType = ConvertType(E->getType());
- Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef());
+ Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef());
Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
@@ -313,7 +313,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *F = CGM.getIntrinsic(Intrinsic::ctlz, ArgType);
llvm::Type *ResultType = ConvertType(E->getType());
- Value *ZeroUndef = Builder.getInt1(Target.isCLZForZeroUndef());
+ Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef());
Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef);
if (Result->getType() != ResultType)
Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true,
@@ -1430,7 +1430,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
const char *Name = getContext().BuiltinInfo.GetName(BuiltinID);
Intrinsic::ID IntrinsicID = Intrinsic::not_intrinsic;
if (const char *Prefix =
- llvm::Triple::getArchTypePrefix(Target.getTriple().getArch()))
+ llvm::Triple::getArchTypePrefix(getTarget().getTriple().getArch()))
IntrinsicID = Intrinsic::getIntrinsicForGCCBuiltin(Prefix, Name);
if (IntrinsicID != Intrinsic::not_intrinsic) {
@@ -1501,7 +1501,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
- switch (Target.getTriple().getArch()) {
+ switch (getTarget().getTriple().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
return EmitARMBuiltinExpr(BuiltinID, E);
@@ -1852,7 +1852,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID,
// Generate target-independent intrinsic; also need to add second argument
// for whether or not clz of zero is undefined; on ARM it isn't.
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ty);
- Ops.push_back(Builder.getInt1(Target.isCLZForZeroUndef()));
+ Ops.push_back(Builder.getInt1(getTarget().isCLZForZeroUndef()));
return EmitNeonCall(F, Ops, "vclz");
}
case ARM::BI__builtin_neon_vcnt_v:
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index faf32e3008..47f3c64840 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -837,12 +837,11 @@ bool CodeGenModule::ReturnTypeUsesFPRet(QualType ResultType) {
default:
return false;
case BuiltinType::Float:
- return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Float);
+ return getTarget().useObjCFPRetForRealType(TargetInfo::Float);
case BuiltinType::Double:
- return getContext().getTargetInfo().useObjCFPRetForRealType(TargetInfo::Double);
+ return getTarget().useObjCFPRetForRealType(TargetInfo::Double);
case BuiltinType::LongDouble:
- return getContext().getTargetInfo().useObjCFPRetForRealType(
- TargetInfo::LongDouble);
+ return getTarget().useObjCFPRetForRealType(TargetInfo::LongDouble);
}
}
@@ -853,7 +852,7 @@ bool CodeGenModule::ReturnTypeUsesFP2Ret(QualType ResultType) {
if (const ComplexType *CT = ResultType->getAs()) {
if (const BuiltinType *BT = CT->getElementType()->getAs()) {
if (BT->getKind() == BuiltinType::LongDouble)
- return getContext().getTargetInfo().useObjCFP2RetForComplexLongDouble();
+ return getTarget().useObjCFP2RetForComplexLongDouble();
}
}
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 2ececb0365..05925567b0 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -710,7 +710,7 @@ void CodeGenFunction::EmitConstructorBody(FunctionArgList &Args) {
// Before we go any further, try the complete->base constructor
// delegation optimization.
if (CtorType == Ctor_Complete && IsConstructorDelegationValid(Ctor) &&
- CGM.getContext().getTargetInfo().getCXXABI().hasConstructorVariants()) {
+ CGM.getTarget().getCXXABI().hasConstructorVariants()) {
if (CGDebugInfo *DI = getDebugInfo())
DI->EmitLocation(Builder, Ctor->getLocEnd());
EmitDelegateCXXConstructorCall(Ctor, Ctor_Base, Args);
@@ -1278,7 +1278,7 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
EnterDtorCleanups(Dtor, Dtor_Complete);
if (!isTryBody &&
- CGM.getContext().getTargetInfo().getCXXABI().hasDestructorVariants()) {
+ CGM.getTarget().getCXXABI().hasDestructorVariants()) {
EmitCXXDestructorCall(Dtor, Dtor_Base, /*ForVirtualBase=*/false,
/*Delegating=*/false, LoadCXXThis());
break;
diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index 711d686150..7a727de5fa 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -642,7 +642,7 @@ llvm::DIType CGDebugInfo::CreatePointerLikeType(unsigned Tag,
// Size is always the size of a pointer. We can't use getTypeSize here
// because that does not return the correct value for references.
unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
+ uint64_t Size = CGM.getTarget().getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(Ty);
return DBuilder.createPointerType(CreatePointeeType(PointeeTy, Unit),
@@ -984,7 +984,7 @@ llvm::DIType CGDebugInfo::getOrCreateInstanceMethodType(
const PointerType *ThisPtrTy = cast(ThisPtr);
QualType PointeeTy = ThisPtrTy->getPointeeType();
unsigned AS = CGM.getContext().getTargetAddressSpace(PointeeTy);
- uint64_t Size = CGM.getContext().getTargetInfo().getPointerWidth(AS);
+ uint64_t Size = CGM.getTarget().getPointerWidth(AS);
uint64_t Align = CGM.getContext().getTypeAlign(ThisPtrTy);
llvm::DIType PointeeType = getOrCreateType(PointeeTy, Unit);
llvm::DIType ThisPtrType = DBuilder.createPointerType(PointeeType, Size, Align);
@@ -2398,7 +2398,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD,
CharUnits Align = CGM.getContext().getDeclAlign(VD);
if (Align > CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().getTargetInfo().getPointerAlign(0))) {
+ CGM.getTarget().getPointerAlign(0))) {
CharUnits FieldOffsetInBytes
= CGM.getContext().toCharUnitsFromBits(FieldOffset);
CharUnits AlignedOffsetInBytes
@@ -2494,7 +2494,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag,
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
// offset of __forwarding field
offset = CGM.getContext().toCharUnitsFromBits(
- CGM.getContext().getTargetInfo().getPointerWidth(0));
+ CGM.getTarget().getPointerWidth(0));
addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity()));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref));
addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus));
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 173ca6cb09..9ad9cf022c 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -900,7 +900,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
CharUnits allocaAlignment = alignment;
if (isByRef)
allocaAlignment = std::max(allocaAlignment,
- getContext().toCharUnitsFromBits(Target.getPointerAlign(0)));
+ getContext().toCharUnitsFromBits(getTarget().getPointerAlign(0)));
Alloc->setAlignment(allocaAlignment.getQuantity());
DeclPtr = Alloc;
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index fd766bf3de..b18fe45296 100644
--- a/lib/CodeGen/CGDeclCXX.cpp
+++ b/lib/CodeGen/CGDeclCXX.cpp
@@ -232,7 +232,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
if (!CGM.getLangOpts().AppleKext) {
// Set the section if needed.
if (const char *Section =
- CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier())
+ CGM.getTarget().getStaticInitSectionSpecifier())
Fn->setSection(Section);
}
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 1ac13c01ed..6b29b3155a 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -1341,7 +1341,7 @@ static CharUnits GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
// Reference values are always non-null and have the width of a pointer.
if (Field->getType()->isReferenceType())
NumNonZeroBytes += CGF.getContext().toCharUnitsFromBits(
- CGF.getContext().getTargetInfo().getPointerWidth(0));
+ CGF.getTarget().getPointerWidth(0));
else
NumNonZeroBytes += GetNumNonZeroBytesInInit(E, CGF);
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index ffd0eb5572..ea1eae8088 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -1634,8 +1634,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
else {
llvm::APFloat F(static_cast(amount));
bool ignored;
- F.convert(CGF.Target.getLongDoubleFormat(), llvm::APFloat::rmTowardZero,
- &ignored);
+ F.convert(CGF.getTarget().getLongDoubleFormat(),
+ llvm::APFloat::rmTowardZero, &ignored);
amt = llvm::ConstantFP::get(VMContext, F);
}
value = Builder.CreateFAdd(value, amt, isInc ? "inc" : "dec");
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 3338b33607..d0e4cd49dc 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -714,7 +714,7 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM,
}
llvm::Triple::ArchType arch =
- CGM.getContext().getTargetInfo().getTriple().getArch();
+ CGM.getTarget().getTriple().getArch();
// Most architectures require memory to fit within a single cache
// line, so the alignment has to be at least the size of the access.
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 6274e1bfe3..d42f5e5f66 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -1949,8 +1949,8 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM,
bool hasUnion = false;
SkipIvars.clear();
IvarsInfo.clear();
- unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
// __isa is the first field in block descriptor and must assume by runtime's
// convention that it is GC'able.
@@ -2077,7 +2077,7 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout,
if (RecFields.empty())
return;
- unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
const FieldDecl *Field = RecFields[i];
@@ -2316,8 +2316,8 @@ llvm::Constant *CGObjCCommonMac::getBitmapBlockLayout(bool ComputeByrefLayout) {
llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy);
if (RunSkipBlockVars.empty())
return nullPtr;
- unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
// Sort on byte position; captures might not be allocated in order,
@@ -2468,8 +2468,8 @@ llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM,
RunSkipBlockVars.clear();
bool hasUnion = false;
- unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits;
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
@@ -4537,8 +4537,8 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI,
if (RecFields.empty())
return;
- unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0);
- unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth();
+ unsigned WordSizeInBits = CGM.getTarget().getPointerWidth(0);
+ unsigned ByteSizeInBits = CGM.getTarget().getCharWidth();
if (!RD && CGM.getLangOpts().ObjCAutoRefCount) {
const FieldDecl *FirstField = RecFields[0];
FirstFieldDelta =
diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp
index abd10a29c9..9c0d5189f8 100644
--- a/lib/CodeGen/CGObjCRuntime.cpp
+++ b/lib/CodeGen/CGObjCRuntime.cpp
@@ -117,7 +117,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF,
// a synthesized ivar can never be a bit-field, so this is safe.
uint64_t FieldBitOffset = LookupFieldBitOffset(CGF.CGM, OID, 0, Ivar);
uint64_t BitOffset = FieldBitOffset % CGF.CGM.getContext().getCharWidth();
- uint64_t AlignmentBits = CGF.CGM.getContext().getTargetInfo().getCharAlign();
+ uint64_t AlignmentBits = CGF.CGM.getTarget().getCharAlign();
uint64_t BitFieldSize = Ivar->getBitWidthValue(CGF.getContext());
CharUnits StorageSize =
CGF.CGM.getContext().toCharUnitsFromBits(
diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp
index 2c6438b0b6..30ab528ffb 100644
--- a/lib/CodeGen/CGRecordLayoutBuilder.cpp
+++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp
@@ -276,7 +276,7 @@ bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout,
uint64_t FirstFieldOffset = Layout.getFieldOffset(FirstFieldNo);
uint64_t NextFieldOffsetInBits = Types.getContext().toBits(NextFieldOffset);
- unsigned CharAlign = Types.getContext().getTargetInfo().getCharAlign();
+ unsigned CharAlign = Types.getTarget().getCharAlign();
assert(FirstFieldOffset % CharAlign == 0 &&
"First field offset is misaligned");
CharUnits FirstFieldOffsetInBytes
@@ -352,7 +352,7 @@ bool CGRecordLayoutBuilder::LayoutBitfields(const ASTRecordLayout &Layout,
assert(EndOffset >= (FirstFieldOffset + TotalBits) &&
"End offset is not past the end of the known storage bits.");
uint64_t SpaceBits = EndOffset - FirstFieldOffset;
- uint64_t LongBits = Types.getContext().getTargetInfo().getLongWidth();
+ uint64_t LongBits = Types.getTarget().getLongWidth();
uint64_t WidenedBits = (StorageBits / LongBits) * LongBits +
llvm::NextPowerOf2(StorageBits % LongBits - 1);
assert(WidenedBits >= StorageBits && "Widening shrunk the bits!");
@@ -455,7 +455,7 @@ CGRecordLayoutBuilder::LayoutUnionField(const FieldDecl *Field,
return 0;
unsigned StorageBits = llvm::RoundUpToAlignment(
- FieldSize, Types.getContext().getTargetInfo().getCharAlign());
+ FieldSize, Types.getTarget().getCharAlign());
CharUnits NumBytesToAppend
= Types.getContext().toCharUnitsFromBits(StorageBits);
@@ -814,7 +814,7 @@ bool CGRecordLayoutBuilder::LayoutFields(const RecordDecl *D) {
// Lay out the virtual bases. The MS ABI uses a different
// algorithm here due to the lack of primary virtual bases.
- if (Types.getContext().getTargetInfo().getCXXABI().hasPrimaryVBases()) {
+ if (Types.getTarget().getCXXABI().hasPrimaryVBases()) {
RD->getIndirectPrimaryBases(IndirectPrimaryBases);
if (Layout.isPrimaryBaseVirtual())
IndirectPrimaryBases.insert(Layout.getPrimaryBase());
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index d10818cf25..dcc423dbdc 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -1451,7 +1451,7 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str,
for (unsigned i = 0, e = StrVal.size()-1; i != e; ++i) {
if (StrVal[i] != '\n') continue;
SourceLocation LineLoc = Str->getLocationOfByte(i+1, SM, LangOpts,
- CGF.Target);
+ CGF.getTarget());
Locs.push_back(llvm::ConstantInt::get(CGF.Int32Ty,
LineLoc.getRawEncoding()));
}
@@ -1471,7 +1471,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
TargetInfo::ConstraintInfo Info(S.getOutputConstraint(i),
S.getOutputName(i));
- bool IsValid = Target.validateOutputConstraint(Info); (void)IsValid;
+ bool IsValid = getTarget().validateOutputConstraint(Info); (void)IsValid;
assert(IsValid && "Failed to parse output constraint");
OutputConstraintInfos.push_back(Info);
}
@@ -1479,8 +1479,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
for (unsigned i = 0, e = S.getNumInputs(); i != e; i++) {
TargetInfo::ConstraintInfo Info(S.getInputConstraint(i),
S.getInputName(i));
- bool IsValid = Target.validateInputConstraint(OutputConstraintInfos.data(),
- S.getNumOutputs(), Info);
+ bool IsValid =
+ getTarget().validateInputConstraint(OutputConstraintInfos.data(),
+ S.getNumOutputs(), Info);
assert(IsValid && "Failed to parse input constraint"); (void)IsValid;
InputConstraintInfos.push_back(Info);
}
@@ -1504,13 +1505,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Simplify the output constraint.
std::string OutputConstraint(S.getOutputConstraint(i));
- OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1, Target);
+ OutputConstraint = SimplifyConstraint(OutputConstraint.c_str() + 1,
+ getTarget());
const Expr *OutExpr = S.getOutputExpr(i);
OutExpr = OutExpr->IgnoreParenNoopCasts(getContext());
OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr,
- Target, CGM, S);
+ getTarget(), CGM, S);
LValue Dest = EmitLValue(OutExpr);
if (!Constraints.empty())
@@ -1591,13 +1593,13 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
// Simplify the input constraint.
std::string InputConstraint(S.getInputConstraint(i));
- InputConstraint = SimplifyConstraint(InputConstraint.c_str(), Target,
+ InputConstraint = SimplifyConstraint(InputConstraint.c_str(), getTarget(),
&OutputConstraintInfos);
InputConstraint =
AddVariableConstraints(InputConstraint,
*InputExpr->IgnoreParenNoopCasts(getContext()),
- Target, CGM, S);
+ getTarget(), CGM, S);
llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints);
@@ -1649,7 +1651,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
StringRef Clobber = S.getClobber(i);
if (Clobber != "memory" && Clobber != "cc")
- Clobber = Target.getNormalizedGCCRegisterName(Clobber);
+ Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
if (i != 0 || NumConstraints != 0)
Constraints += ',';
@@ -1660,7 +1662,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
}
// Add machine specific clobbers
- std::string MachineClobbers = Target.getClobbers();
+ std::string MachineClobbers = getTarget().getClobbers();
if (!MachineClobbers.empty()) {
if (!Constraints.empty())
Constraints += ',';
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 2c3cabe985..cda3ce0286 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -31,8 +31,7 @@ using namespace clang;
using namespace CodeGen;
CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
- : CodeGenTypeCache(cgm), CGM(cgm),
- Target(CGM.getContext().getTargetInfo()),
+ : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
Builder(cgm.getModule().getContext()),
SanitizePerformTypeCheck(CGM.getSanOpts().Null |
CGM.getSanOpts().Alignment |
@@ -279,8 +278,8 @@ void CodeGenFunction::EmitFunctionInstrumentation(const char *Fn) {
void CodeGenFunction::EmitMCountInstrumentation() {
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false);
- llvm::Constant *MCountFn = CGM.CreateRuntimeFunction(FTy,
- Target.getMCountName());
+ llvm::Constant *MCountFn =
+ CGM.CreateRuntimeFunction(FTy, getTarget().getMCountName());
EmitNounwindRuntimeCall(MCountFn);
}
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 941eebe882..f4ac0866c8 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1300,6 +1300,7 @@ public:
return getInvokeDestImpl();
}
+ const TargetInfo &getTarget() const { return Target; }
llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
//===--------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 7990a491c0..6c2578f336 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -55,7 +55,7 @@ using namespace CodeGen;
static const char AnnotationSection[] = "llvm.metadata";
static CGCXXABI &createCXXABI(CodeGenModule &CGM) {
- switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
+ switch (CGM.getTarget().getCXXABI().getKind()) {
case TargetCXXABI::GenericAArch64:
case TargetCXXABI::GenericARM:
case TargetCXXABI::iOS:
@@ -73,16 +73,14 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO,
const TargetOptions &TO, llvm::Module &M,
const llvm::DataLayout &TD,
DiagnosticsEngine &diags)
- : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TargetOpts(TO),
- TheModule(M), TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags),
- ABI(createCXXABI(*this)),
- Types(*this),
- TBAA(0),
- VTables(*this), ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
+ : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M),
+ Diags(diags), TheDataLayout(TD), Target(C.getTargetInfo()),
+ ABI(createCXXABI(*this)), VMContext(M.getContext()), TBAA(0),
+ TheTargetCodeGenInfo(0), Types(*this), VTables(*this),
+ ObjCRuntime(0), OpenCLRuntime(0), CUDARuntime(0),
DebugInfo(0), ARCData(0), NoObjCARCExceptionsMetadata(0),
RRData(0), CFConstantStringClassRef(0),
ConstantStringClassRef(0), NSConstantStringType(0),
- VMContext(M.getContext()),
NSConcreteGlobalBlock(0), NSConcreteStackBlock(0),
BlockObjectAssign(0), BlockObjectDispose(0),
BlockDescriptorType(0), GenericBlockLiteralType(0),
@@ -256,10 +254,6 @@ void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
}
-bool CodeGenModule::isTargetDarwin() const {
- return getContext().getTargetInfo().getTriple().isOSDarwin();
-}
-
void CodeGenModule::Error(SourceLocation loc, StringRef error) {
unsigned diagID = getDiags().getCustomDiagID(DiagnosticsEngine::Error, error);
getDiags().Report(Context.getFullLoc(loc), diagID);
@@ -2361,7 +2355,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) {
GV = new llvm::GlobalVariable(getModule(), C->getType(), true,
llvm::GlobalVariable::PrivateLinkage, C,
"_unnamed_cfstring_");
- if (const char *Sect = getContext().getTargetInfo().getCFStringSection())
+ if (const char *Sect = getTarget().getCFStringSection())
GV->setSection(Sect);
Entry.setValue(GV);
@@ -2486,8 +2480,8 @@ CodeGenModule::GetAddrOfConstantString(const StringLiteral *Literal) {
// FIXME. Fix section.
if (const char *Sect =
LangOpts.ObjCRuntime.isNonFragile()
- ? getContext().getTargetInfo().getNSStringNonFragileABISection()
- : getContext().getTargetInfo().getNSStringSection())
+ ? getTarget().getNSStringNonFragileABISection()
+ : getTarget().getNSStringSection())
GV->setSection(Sect);
Entry.setValue(GV);
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index ab499ae9b4..c1f951614a 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -233,15 +233,22 @@ class CodeGenModule : public CodeGenTypeCache {
ASTContext &Context;
const LangOptions &LangOpts;
const CodeGenOptions &CodeGenOpts;
- const TargetOptions &TargetOpts;
llvm::Module &TheModule;
- const llvm::DataLayout &TheDataLayout;
- mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
DiagnosticsEngine &Diags;
+ const llvm::DataLayout &TheDataLayout;
+ const TargetInfo &Target;
CGCXXABI &ABI;
- CodeGenTypes Types;
- CodeGenTBAA *TBAA;
+ llvm::LLVMContext &VMContext;
+ CodeGenTBAA *TBAA;
+
+ mutable const TargetCodeGenInfo *TheTargetCodeGenInfo;
+
+ // This should not be moved earlier, since its initialization depends on some
+ // of the previous reference members being already initialized and also checks
+ // if TheTargetCodeGenInfo is NULL
+ CodeGenTypes Types;
+
/// VTables - Holds information about C++ vtables.
CodeGenVTables VTables;
friend class CodeGenVTables;
@@ -255,8 +262,8 @@ class CodeGenModule : public CodeGenTypeCache {
RREntrypoints *RRData;
// WeakRefReferences - A set of references that have only been seen via
- // a weakref so far. This is used to remove the weak of the reference if we ever
- // see a direct reference or a definition.
+ // a weakref so far. This is used to remove the weak of the reference if we
+ // ever see a direct reference or a definition.
llvm::SmallPtrSet WeakRefReferences;
/// DeferredDecls - This contains all the decls which have definitions but
@@ -369,7 +376,6 @@ class CodeGenModule : public CodeGenTypeCache {
bool isTriviallyRecursive(const FunctionDecl *F);
bool shouldEmitFunction(const FunctionDecl *F);
- llvm::LLVMContext &VMContext;
/// @name Cache for Blocks Runtime Globals
/// @{
@@ -433,9 +439,6 @@ public:
return *CUDARuntime;
}
- /// getCXXABI() - Return a reference to the configured C++ ABI.
- CGCXXABI &getCXXABI() { return ABI; }
-
ARCEntrypoints &getARCEntrypoints() const {
assert(getLangOpts().ObjCAutoRefCount && ARCData != 0);
return *ARCData;
@@ -489,21 +492,24 @@ public:
}
ASTContext &getContext() const { return Context; }
- const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
const LangOptions &getLangOpts() const { return LangOpts; }
+ const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
llvm::Module &getModule() const { return TheModule; }
- CodeGenTypes &getTypes() { return Types; }
- CodeGenVTables &getVTables() { return VTables; }
- VTableContext &getVTableContext() { return VTables.getVTableContext(); }
DiagnosticsEngine &getDiags() const { return Diags; }
const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
- const TargetInfo &getTarget() const { return Context.getTargetInfo(); }
+ const TargetInfo &getTarget() const { return Target; }
+ CGCXXABI &getCXXABI() { return ABI; }
llvm::LLVMContext &getLLVMContext() { return VMContext; }
- const TargetCodeGenInfo &getTargetCodeGenInfo();
- bool isTargetDarwin() const;
-
+
bool shouldUseTBAA() const { return TBAA != 0; }
+ const TargetCodeGenInfo &getTargetCodeGenInfo();
+
+ CodeGenTypes &getTypes() { return Types; }
+
+ CodeGenVTables &getVTables() { return VTables; }
+ VTableContext &getVTableContext() { return VTables.getVTableContext(); }
+
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
llvm::MDNode *getTBAAStructInfo(QualType QTy);
@@ -574,8 +580,8 @@ public:
return GetAddrOfGlobalVar(cast(GD.getDecl()));
}
- /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the given
- /// type. If a variable with a different type already exists then a new
+ /// CreateOrReplaceCXXRuntimeVariable - Will return a global variable of the
+ /// given type. If a variable with a different type already exists then a new
/// variable with the right type will be created and all uses of the old
/// variable will be replaced with a bitcast to the new variable.
llvm::GlobalVariable *
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 8fc78e3de6..6f6e52c033 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -28,12 +28,12 @@
using namespace clang;
using namespace CodeGen;
-CodeGenTypes::CodeGenTypes(CodeGenModule &CGM)
- : Context(CGM.getContext()), Target(Context.getTargetInfo()),
- TheModule(CGM.getModule()), TheDataLayout(CGM.getDataLayout()),
- TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()),
- TheCXXABI(CGM.getCXXABI()),
- CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) {
+CodeGenTypes::CodeGenTypes(CodeGenModule &cgm)
+ : CGM(cgm), Context(cgm.getContext()), TheModule(cgm.getModule()),
+ TheDataLayout(cgm.getDataLayout()),
+ Target(cgm.getTarget()), TheCXXABI(cgm.getCXXABI()),
+ CodeGenOpts(cgm.getCodeGenOpts()),
+ TheABIInfo(cgm.getTargetCodeGenInfo().getABIInfo()) {
SkippedLayout = false;
}
diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h
index 11fd76fb19..452375f374 100644
--- a/lib/CodeGen/CodeGenTypes.h
+++ b/lib/CodeGen/CodeGenTypes.h
@@ -60,14 +60,17 @@ namespace CodeGen {
class CodeGenTypes {
public:
// Some of this stuff should probably be left on the CGM.
+ CodeGenModule &CGM;
ASTContext &Context;
- const TargetInfo &Target;
llvm::Module &TheModule;
const llvm::DataLayout &TheDataLayout;
- const ABIInfo &TheABIInfo;
+ const TargetInfo &Target;
CGCXXABI &TheCXXABI;
const CodeGenOptions &CodeGenOpts;
- CodeGenModule &CGM;
+
+ // This should not be moved earlier, since its initialization depends on some
+ // of the previous reference members being already initialized
+ const ABIInfo &TheABIInfo;
private:
/// The opaque type map for Objective-C interfaces. All direct
@@ -107,14 +110,14 @@ private:
llvm::DenseMap TypeCache;
public:
- CodeGenTypes(CodeGenModule &CGM);
+ CodeGenTypes(CodeGenModule &cgm);
~CodeGenTypes();
const llvm::DataLayout &getDataLayout() const { return TheDataLayout; }
- const TargetInfo &getTarget() const { return Target; }
ASTContext &getContext() const { return Context; }
const ABIInfo &getABIInfo() const { return TheABIInfo; }
const CodeGenOptions &getCodeGenOpts() const { return CodeGenOpts; }
+ const TargetInfo &getTarget() const { return Target; }
CGCXXABI &getCXXABI() const { return TheCXXABI; }
llvm::LLVMContext &getLLVMContext() { return TheModule.getContext(); }
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 25cd5f58f8..496a0862c8 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -177,7 +177,7 @@ public:
}
CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
- switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
+ switch (CGM.getTarget().getCXXABI().getKind()) {
// For IR-generation purposes, there's no significant difference
// between the ARM and iOS ABIs.
case TargetCXXABI::GenericARM:
diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp
index d0b4918c67..ed89e24008 100644
--- a/lib/CodeGen/TargetInfo.cpp
+++ b/lib/CodeGen/TargetInfo.cpp
@@ -55,6 +55,9 @@ const llvm::DataLayout &ABIInfo::getDataLayout() const {
return CGT.getDataLayout();
}
+const TargetInfo &ABIInfo::getTarget() const {
+ return CGT.getTarget();
+}
void ABIArgInfo::dump() const {
raw_ostream &OS = llvm::errs();
@@ -551,8 +554,7 @@ public:
int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const {
// Darwin uses different dwarf register numbers for EH.
- if (CGM.isTargetDarwin()) return 5;
-
+ if (CGM.getTarget().getTriple().isOSDarwin()) return 5;
return 4;
}
@@ -1020,7 +1022,7 @@ bool X86_32TargetCodeGenInfo::initDwarfEHRegSizeTable(
// 8 is %eip.
AssignToArrayRange(Builder, Address, Four8, 0, 8);
- if (CGF.CGM.isTargetDarwin()) {
+ if (CGF.CGM.getTarget().getTriple().isOSDarwin()) {
// 12-16 are st(0..4). Not sure why we stop at 4.
// These have size 16, which is sizeof(long double) on
// platforms with 8-byte alignment for that type.
@@ -1145,7 +1147,7 @@ class X86_64ABIInfo : public ABIInfo {
/// required strict binary compatibility with older versions of GCC
/// may need to exempt themselves.
bool honorsRevision0_98() const {
- return !getContext().getTargetInfo().getTriple().isOSDarwin();
+ return !getTarget().getTriple().isOSDarwin();
}
bool HasAVX;
@@ -1369,8 +1371,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Current = Integer;
} else if ((k == BuiltinType::Float || k == BuiltinType::Double) ||
(k == BuiltinType::LongDouble &&
- getContext().getTargetInfo().getTriple().getOS() ==
- llvm::Triple::NaCl)) {
+ getTarget().getTriple().getOS() == llvm::Triple::NaCl)) {
Current = SSE;
} else if (k == BuiltinType::LongDouble) {
Lo = X87;
@@ -1458,8 +1459,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase,
Current = SSE;
else if (ET == getContext().DoubleTy ||
(ET == getContext().LongDoubleTy &&
- getContext().getTargetInfo().getTriple().getOS() ==
- llvm::Triple::NaCl))
+ getTarget().getTriple().getOS() == llvm::Triple::NaCl))
Lo = Hi = SSE;
else if (ET == getContext().LongDoubleTy)
Current = ComplexX87;
@@ -2514,9 +2514,7 @@ ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty) const {
return ABIArgInfo::getIndirect(0, /*ByVal=*/false);
// FIXME: mingw-w64-gcc emits 128-bit struct as i128
- if (Size == 128 &&
- getContext().getTargetInfo().getTriple().getOS()
- == llvm::Triple::MinGW32)
+ if (Size == 128 && getTarget().getTriple().getOS() == llvm::Triple::MinGW32)
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
@@ -2946,8 +2944,7 @@ public:
}
bool isEABI() const {
- StringRef Env =
- getContext().getTargetInfo().getTriple().getEnvironmentName();
+ StringRef Env = getTarget().getTriple().getEnvironmentName();
return (Env == "gnueabi" || Env == "eabi" ||
Env == "android" || Env == "androideabi");
}
@@ -3046,7 +3043,7 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const {
/// Return the default calling convention that LLVM will use.
llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC() const {
// The default calling convention that LLVM will infer.
- if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf")
+ if (getTarget().getTriple().getEnvironmentName()=="gnueabihf")
return llvm::CallingConv::ARM_AAPCS_VFP;
else if (isEABI())
return llvm::CallingConv::ARM_AAPCS;
@@ -4538,7 +4535,7 @@ llvm::Value* MipsABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
int64_t TypeAlign = getContext().getTypeAlign(Ty) / 8;
llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
llvm::Value *AddrTyped;
- unsigned PtrWidth = getContext().getTargetInfo().getPointerWidth(0);
+ unsigned PtrWidth = getTarget().getPointerWidth(0);
llvm::IntegerType *IntTy = (PtrWidth == 32) ? CGF.Int32Ty : CGF.Int64Ty;
if (TypeAlign > MinABIStackAlignInBytes) {
@@ -4799,7 +4796,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
if (TheTargetCodeGenInfo)
return *TheTargetCodeGenInfo;
- const llvm::Triple &Triple = getContext().getTargetInfo().getTriple();
+ const llvm::Triple &Triple = getTarget().getTriple();
switch (Triple.getArch()) {
default:
return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types));
@@ -4821,10 +4818,11 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::thumb:
{
ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS;
- if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0)
+ if (strcmp(getTarget().getABI(), "apcs-gnu") == 0)
Kind = ARMABIInfo::APCS;
else if (CodeGenOpts.FloatABI == "hard" ||
- (CodeGenOpts.FloatABI != "soft" && Triple.getEnvironment()==llvm::Triple::GNUEABIHF))
+ (CodeGenOpts.FloatABI != "soft" &&
+ Triple.getEnvironment() == llvm::Triple::GNUEABIHF))
Kind = ARMABIInfo::AAPCS_VFP;
switch (Triple.getOS()) {
@@ -4889,7 +4887,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
}
case llvm::Triple::x86_64: {
- bool HasAVX = strcmp(getContext().getTargetInfo().getABI(), "avx") == 0;
+ bool HasAVX = strcmp(getTarget().getABI(), "avx") == 0;
switch (Triple.getOS()) {
case llvm::Triple::Win32:
@@ -4897,7 +4895,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
case llvm::Triple::Cygwin:
return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types));
case llvm::Triple::NaCl:
- return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX));
+ return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types,
+ HasAVX));
default:
return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types,
HasAVX));
--
cgit v1.2.3-70-g09d2
From c3bf52ced9652f555aa0767bb822ec4c64546212 Mon Sep 17 00:00:00 2001
From: Richard Smith
Date: Sat, 20 Apr 2013 22:23:05 +0000
Subject: C++1y: Allow aggregates to have default initializers.
Add a CXXDefaultInitExpr, analogous to CXXDefaultArgExpr, and use it both in
CXXCtorInitializers and in InitListExprs to represent a default initializer.
There's an additional complication here: because the default initializer can
refer to the initialized object via its 'this' pointer, we need to make sure
that 'this' points to the right thing within the evaluation.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179958 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/AST/DeclCXX.h | 14 +---
include/clang/AST/ExprCXX.h | 47 ++++++++++++++
include/clang/AST/RecursiveASTVisitor.h | 1 +
include/clang/Basic/StmtNodes.td | 1 +
include/clang/Serialization/ASTBitCodes.h | 1 +
lib/AST/DeclCXX.cpp | 7 +-
lib/AST/DeclPrinter.cpp | 2 +-
lib/AST/Expr.cpp | 26 +++++++-
lib/AST/ExprCXX.cpp | 11 ++++
lib/AST/ExprClassification.cpp | 4 ++
lib/AST/ExprConstant.cpp | 38 ++++++++++-
lib/AST/ItaniumMangle.cpp | 4 ++
lib/AST/StmtPrinter.cpp | 6 +-
lib/AST/StmtProfile.cpp | 5 ++
lib/Analysis/CFG.cpp | 5 ++
lib/CodeGen/CGClass.cpp | 1 +
lib/CodeGen/CGExpr.cpp | 4 ++
lib/CodeGen/CGExprAgg.cpp | 9 ++-
lib/CodeGen/CGExprComplex.cpp | 4 ++
lib/CodeGen/CGExprConstant.cpp | 6 ++
lib/CodeGen/CGExprScalar.cpp | 4 ++
lib/CodeGen/CodeGenFunction.cpp | 1 +
lib/CodeGen/CodeGenFunction.h | 41 ++++++++++++
lib/Sema/SemaDeclCXX.cpp | 8 ++-
lib/Sema/SemaExceptionSpec.cpp | 7 +-
lib/Sema/SemaInit.cpp | 59 ++++++++++++++---
lib/Sema/TreeTransform.h | 26 ++++++++
lib/Serialization/ASTReaderStmt.cpp | 9 +++
lib/Serialization/ASTWriterStmt.cpp | 7 ++
lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 +
test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp | 13 ++--
test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp | 23 +++++++
test/CodeGenCXX/cxx1y-initializer-aggregate.cpp | 74 ++++++++++++++++++++++
test/SemaCXX/cxx1y-initializer-aggregates.cpp | 63 ++++++++++++++++++
tools/libclang/CXCursor.cpp | 1 +
tools/libclang/RecursiveASTVisitor.h | 1 +
www/cxx_status.html | 2 +-
37 files changed, 495 insertions(+), 41 deletions(-)
create mode 100644 test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp
create mode 100644 test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
create mode 100644 test/SemaCXX/cxx1y-initializer-aggregates.cpp
(limited to 'lib/CodeGen/CGClass.cpp')
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index 5506d211cc..eb6035680b 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1754,8 +1754,6 @@ class CXXCtorInitializer {
/// \brief The argument used to initialize the base or member, which may
/// end up constructing an object (when multiple arguments are involved).
- /// If 0, this is a field initializer, and the in-class member initializer
- /// will be used.
Stmt *Init;
/// LParenLoc - Location of the left paren of the ctor-initializer.
@@ -1840,7 +1838,7 @@ public:
/// implicit ctor initializer generated for a field with an initializer
/// defined on the member declaration.
bool isInClassMemberInitializer() const {
- return !Init;
+ return isa(Init);
}
/// isDelegatingInitializer - Returns true when this initializer is creating
@@ -1967,14 +1965,8 @@ public:
getNumArrayIndices());
}
- /// \brief Get the initializer. This is 0 if this is an in-class initializer
- /// for a non-static data member which has not yet been parsed.
- Expr *getInit() const {
- if (!Init)
- return getAnyMember()->getInClassInitializer();
-
- return static_cast(Init);
- }
+ /// \brief Get the initializer.
+ Expr *getInit() const { return static_cast(Init); }
};
/// CXXConstructorDecl - Represents a C++ constructor within a
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 3189426f9d..91e5b21eac 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -884,6 +884,53 @@ public:
friend class ASTStmtWriter;
};
+/// \brief This wraps a use of a C++ default initializer (technically,
+/// a brace-or-equal-initializer for a non-static data member) when it
+/// is implicitly used in a mem-initializer-list in a constructor
+/// (C++11 [class.base.init]p8) or in aggregate initialization
+/// (C++1y [dcl.init.aggr]p7).
+class CXXDefaultInitExpr : public Expr {
+ /// \brief The field whose default is being used.
+ FieldDecl *Field;
+
+ /// \brief The location where the default initializer expression was used.
+ SourceLocation Loc;
+
+ CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc, FieldDecl *Field,
+ QualType T);
+
+ CXXDefaultInitExpr(EmptyShell Empty) : Expr(CXXDefaultInitExprClass, Empty) {}
+
+public:
+ // Field is the non-static data member whose default initializer is used
+ // by this expression.
+ static CXXDefaultInitExpr *Create(ASTContext &C, SourceLocation Loc,
+ FieldDecl *Field) {
+ return new (C) CXXDefaultInitExpr(C, Loc, Field, Field->getType());
+ }
+
+ // Get the field whose initializer will be used.
+ FieldDecl *getField() { return Field; }
+ const FieldDecl *getField() const { return Field; }
+
+ // Get the initialization expression that will be used.
+ const Expr *getExpr() const { return Field->getInClassInitializer(); }
+ Expr *getExpr() { return Field->getInClassInitializer(); }
+
+ SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
+ SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == CXXDefaultInitExprClass;
+ }
+
+ // Iterators
+ child_range children() { return child_range(); }
+
+ friend class ASTReader;
+ friend class ASTStmtReader;
+};
+
/// CXXTemporary - Represents a C++ temporary.
class CXXTemporary {
/// Destructor - The destructor that needs to be called.
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index df41b6fa5a..eb5a8123c2 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2170,6 +2170,7 @@ DEF_TRAVERSE_STMT(CompoundLiteralExpr, {
DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
+DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index ad25e57c89..cbfce83c4b 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -108,6 +108,7 @@ def CXXNullPtrLiteralExpr : DStmt;
def CXXThisExpr : DStmt;
def CXXThrowExpr : DStmt;
def CXXDefaultArgExpr : DStmt;
+def CXXDefaultInitExpr : DStmt;
def CXXScalarValueInitExpr : DStmt;
def CXXNewExpr : DStmt;
def CXXDeleteExpr : DStmt;
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index 9f5e8b1224..81f8980425 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -1267,6 +1267,7 @@ namespace clang {
EXPR_CXX_THIS, // CXXThisExpr
EXPR_CXX_THROW, // CXXThrowExpr
EXPR_CXX_DEFAULT_ARG, // CXXDefaultArgExpr
+ EXPR_CXX_DEFAULT_INIT, // CXXDefaultInitExpr
EXPR_CXX_BIND_TEMPORARY, // CXXBindTemporaryExpr
EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 2c7c4d335d..ece831571c 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -505,7 +505,7 @@ void CXXRecordDecl::addedMember(Decl *D) {
// C++ [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-declared
// constructors [...].
- // C++0x [dcl.init.aggr]p1:
+ // C++11 [dcl.init.aggr]p1:
// An aggregate is an array or a class with no user-provided
// constructors [...].
if (getASTContext().getLangOpts().CPlusPlus11
@@ -690,7 +690,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
// C++11 [dcl.init.aggr]p1:
// An aggregate is a [...] class with [...] no
// brace-or-equal-initializers for non-static data members.
- data().Aggregate = false;
+ //
+ // This rule was removed in C++1y.
+ if (!getASTContext().getLangOpts().CPlusPlus1y)
+ data().Aggregate = false;
// C++11 [class]p10:
// A POD struct is [...] a trivial class.
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 995925350c..bcc4e3865a 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -487,7 +487,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(),
E = CDecl->init_end();
B != E; ++B) {
- CXXCtorInitializer * BMInitializer = (*B);
+ CXXCtorInitializer *BMInitializer = (*B);
if (BMInitializer->isInClassMemberInitializer())
continue;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 748d3084fe..1303fb0cee 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -100,11 +100,20 @@ Expr::skipRValueSubobjectAdjustments(
const Expr *
Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const {
const Expr *E = this;
+
+ // This might be a default initializer for a reference member. Walk over the
+ // wrapper node for that.
+ if (const CXXDefaultInitExpr *DAE = dyn_cast(E))
+ E = DAE->getExpr();
+
// Look through single-element init lists that claim to be lvalues. They're
// just syntactic wrappers in this case.
if (const InitListExpr *ILE = dyn_cast(E)) {
- if (ILE->getNumInits() == 1 && ILE->isGLValue())
+ if (ILE->getNumInits() == 1 && ILE->isGLValue()) {
E = ILE->getInit(0);
+ if (const CXXDefaultInitExpr *DAE = dyn_cast(E))
+ E = DAE->getExpr();
+ }
}
// Look through expressions for materialized temporaries (for now).
@@ -2174,6 +2183,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case CXXDefaultArgExprClass:
return (cast(this)
->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx));
+ case CXXDefaultInitExprClass:
+ return (cast(this)
+ ->getExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx));
case CXXNewExprClass:
// FIXME: In theory, there might be new expressions that don't have side
@@ -2851,6 +2863,12 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const {
case CXXDefaultArgExprClass:
return cast(this)->getExpr()->HasSideEffects(Ctx);
+ case CXXDefaultInitExprClass:
+ if (const Expr *E = cast(this)->getExpr())
+ return E->HasSideEffects(Ctx);
+ // If we've not yet parsed the initializer, assume it has side-effects.
+ return true;
+
case CXXDynamicCastExprClass: {
// A dynamic_cast expression has side-effects if it can throw.
const CXXDynamicCastExpr *DCE = cast(this);
@@ -3038,8 +3056,12 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast(this)) {
- // See through default argument expressions
+ // See through default argument expressions.
return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC);
+ } else if (const CXXDefaultInitExpr *DefaultInit
+ = dyn_cast(this)) {
+ // See through default initializer expressions.
+ return DefaultInit->getExpr()->isNullPointerConstant(Ctx, NPC);
} else if (isa(this)) {
// The GNU __null extension is always a null pointer constant.
return NPCK_GNUNull;
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 12a47fcd78..277c8c09a5 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -704,6 +704,17 @@ CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc,
SubExpr);
}
+CXXDefaultInitExpr::CXXDefaultInitExpr(ASTContext &C, SourceLocation Loc,
+ FieldDecl *Field, QualType T)
+ : Expr(CXXDefaultInitExprClass, T.getNonLValueExprType(C),
+ T->isLValueReferenceType() ? VK_LValue : T->isRValueReferenceType()
+ ? VK_XValue
+ : VK_RValue,
+ /*FIXME*/ OK_Ordinary, false, false, false, false),
+ Field(Field), Loc(Loc) {
+ assert(Field->hasInClassInitializer());
+}
+
CXXTemporary *CXXTemporary::Create(ASTContext &C,
const CXXDestructorDecl *Destructor) {
return new (C) CXXTemporary(Destructor);
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index c2a35f42c1..bcb6d4e809 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -298,6 +298,10 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::CXXDefaultArgExprClass:
return ClassifyInternal(Ctx, cast(E)->getExpr());
+ // Same idea for default initializers.
+ case Expr::CXXDefaultInitExprClass:
+ return ClassifyInternal(Ctx, cast(E)->getExpr());
+
// Same idea for temporary binding.
case Expr::CXXBindTemporaryExprClass:
return ClassifyInternal(Ctx, cast(E)->getSubExpr());
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 3675b2ff44..4e468806dc 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -301,6 +301,22 @@ namespace {
~CallStackFrame();
};
+ /// Temporarily override 'this'.
+ class ThisOverrideRAII {
+ public:
+ ThisOverrideRAII(CallStackFrame &Frame, const LValue *NewThis, bool Enable)
+ : Frame(Frame), OldThis(Frame.This) {
+ if (Enable)
+ Frame.This = NewThis;
+ }
+ ~ThisOverrideRAII() {
+ Frame.This = OldThis;
+ }
+ private:
+ CallStackFrame &Frame;
+ const LValue *OldThis;
+ };
+
/// A partial diagnostic which we might know in advance that we are not going
/// to emit.
class OptionalDiagnostic {
@@ -2397,6 +2413,8 @@ public:
{ return StmtVisitorTy::Visit(E->getReplacement()); }
RetTy VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
{ return StmtVisitorTy::Visit(E->getExpr()); }
+ RetTy VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E)
+ { return StmtVisitorTy::Visit(E->getExpr()); }
// We cannot create any objects for which cleanups are required, so there is
// nothing to do here; all cleanups must come from unevaluated subexpressions.
RetTy VisitExprWithCleanups(const ExprWithCleanups *E)
@@ -3398,12 +3416,20 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// If the initializer list for a union does not contain any elements, the
// first element of the union is value-initialized.
+ // FIXME: The element should be initialized from an initializer list.
+ // Is this difference ever observable for initializer lists which
+ // we don't build?
ImplicitValueInitExpr VIE(Field->getType());
const Expr *InitExpr = E->getNumInits() ? E->getInit(0) : &VIE;
LValue Subobject = This;
if (!HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout))
return false;
+
+ // Temporarily override This, in case there's a CXXDefaultInitExpr in here.
+ ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This,
+ isa(InitExpr));
+
return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
}
@@ -3433,10 +3459,14 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// Perform an implicit value-initialization for members beyond the end of
// the initializer list.
ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
+ const Expr *Init = HaveInit ? E->getInit(ElementNo++) : &VIE;
- if (!EvaluateInPlace(
- Result.getStructField(Field->getFieldIndex()),
- Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) {
+ // Temporarily override This, in case there's a CXXDefaultInitExpr in here.
+ ThisOverrideRAII ThisOverride(*Info.CurrentCall, &This,
+ isa(Init));
+
+ if (!EvaluateInPlace(Result.getStructField(Field->getFieldIndex()), Info,
+ Subobject, Init)) {
if (!Info.keepEvaluatingAfterFailure())
return false;
Success = false;
@@ -6807,6 +6837,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
}
case Expr::CXXDefaultArgExprClass:
return CheckICE(cast(E)->getExpr(), Ctx);
+ case Expr::CXXDefaultInitExprClass:
+ return CheckICE(cast(E)->getExpr(), Ctx);
case Expr::ChooseExprClass: {
return CheckICE(cast(E)->getChosenSubExpr(Ctx), Ctx);
}
diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp
index e82b017e4a..0b77933f0b 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -2473,6 +2473,10 @@ recurse:
mangleExpression(cast(E)->getExpr(), Arity);
break;
+ case Expr::CXXDefaultInitExprClass:
+ mangleExpression(cast(E)->getExpr(), Arity);
+ break;
+
case Expr::SubstNonTypeTemplateParmExprClass:
mangleExpression(cast(E)->getReplacement(),
Arity);
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 1b2285c794..95bacb64b3 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1314,7 +1314,11 @@ void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) {
}
void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) {
- // Nothing to print: we picked up the default argument
+ // Nothing to print: we picked up the default argument.
+}
+
+void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) {
+ // Nothing to print: we picked up the default initializer.
}
void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index d99400c603..8ade242d56 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -789,6 +789,11 @@ void StmtProfiler::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) {
VisitDecl(S->getParam());
}
+void StmtProfiler::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getField());
+}
+
void StmtProfiler::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
VisitExpr(S);
VisitDecl(
diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp
index 1adb8b84e4..096c7a080b 100644
--- a/lib/Analysis/CFG.cpp
+++ b/lib/Analysis/CFG.cpp
@@ -1085,11 +1085,16 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) {
return VisitExprWithCleanups(cast(S), asc);
case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXDefaultInitExprClass:
// FIXME: The expression inside a CXXDefaultArgExpr is owned by the
// called function's declaration, not by the caller. If we simply add
// this expression to the CFG, we could end up with the same Expr
// appearing multiple times.
// PR13385 /
+ //
+ // It's likewise possible for multiple CXXDefaultInitExprs for the same
+ // expression to be used in the same function (through aggregate
+ // initialization).
return VisitStmt(S, asc);
case Stmt::CXXBindTemporaryExprClass:
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 05925567b0..2b9a55b2a6 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1139,6 +1139,7 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD,
InitializeVTablePointers(ClassDecl);
// And finally, initialize class members.
+ FieldConstructionScope FCS(*this, CXXThisValue);
ConstructorMemcpyizer CM(*this, CD, Args);
for (; B != E; B++) {
CXXCtorInitializer *Member = (*B);
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index a0725b5f9c..ea13de17ab 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -903,6 +903,10 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
return EmitNullInitializationLValue(cast(E));
case Expr::CXXDefaultArgExprClass:
return EmitLValue(cast(E)->getExpr());
+ case Expr::CXXDefaultInitExprClass: {
+ CXXDefaultInitExprScope Scope(*this);
+ return EmitLValue(cast(E)->getExpr());
+ }
case Expr::CXXTypeidExprClass:
return EmitCXXTypeidLValue(cast(E));
diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp
index 6b29b3155a..b974e1dcc6 100644
--- a/lib/CodeGen/CGExprAgg.cpp
+++ b/lib/CodeGen/CGExprAgg.cpp
@@ -170,6 +170,10 @@ public:
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
Visit(DAE->getExpr());
}
+ void VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
+ CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
+ Visit(DIE->getExpr());
+ }
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E);
void VisitCXXConstructExpr(const CXXConstructExpr *E);
void VisitLambdaExpr(LambdaExpr *E);
@@ -1189,7 +1193,10 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
// the optimizer, especially with bitfields.
unsigned NumInitElements = E->getNumInits();
RecordDecl *record = E->getType()->castAs()->getDecl();
-
+
+ // Prepare a 'this' for CXXDefaultInitExprs.
+ CodeGenFunction::FieldConstructionScope FCS(CGF, Dest.getAddr());
+
if (record->isUnion()) {
// Only initialize one field of a union. The field itself is
// specified by the initializer list.
diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp
index 5fc73aa790..36f974a313 100644
--- a/lib/CodeGen/CGExprComplex.cpp
+++ b/lib/CodeGen/CGExprComplex.cpp
@@ -182,6 +182,10 @@ public:
ComplexPairTy VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
return Visit(DAE->getExpr());
}
+ ComplexPairTy VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
+ CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
+ return Visit(DIE->getExpr());
+ }
ComplexPairTy VisitExprWithCleanups(ExprWithCleanups *E) {
CGF.enterFullExpression(E);
CodeGenFunction::RunCleanupsScope Scope(CGF);
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index faaf6468f1..f5c8187c26 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -757,6 +757,12 @@ public:
return Visit(DAE->getExpr());
}
+ llvm::Constant *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
+ // No need for a DefaultInitExprScope: we don't handle 'this' in a
+ // constant expression.
+ return Visit(DIE->getExpr());
+ }
+
llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) {
return Visit(E->GetTemporaryExpr());
}
diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp
index ea1eae8088..c1c252d12b 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -344,6 +344,10 @@ public:
Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
return Visit(DAE->getExpr());
}
+ Value *VisitCXXDefaultInitExpr(CXXDefaultInitExpr *DIE) {
+ CodeGenFunction::CXXDefaultInitExprScope Scope(CGF);
+ return Visit(DIE->getExpr());
+ }
Value *VisitCXXThisExpr(CXXThisExpr *TE) {
return CGF.LoadCXXThis();
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index cda3ce0286..a12e7dc445 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -45,6 +45,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
DidCallStackSave(false),
IndirectBranch(0), SwitchInsn(0), CaseRangeBlock(0), UnreachableBlock(0),
CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0),
+ CXXDefaultInitExprThis(0),
CXXStructorImplicitParamDecl(0), CXXStructorImplicitParamValue(0),
OutermostConditional(0), CurLexicalScope(0), TerminateLandingPad(0),
TerminateHandler(0), TrapBB(0) {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 6e2d62760f..f0c2c1e672 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1206,12 +1206,53 @@ private:
/// lazily by getUnreachableBlock().
llvm::BasicBlock *UnreachableBlock;
+public:
+ /// A scope within which we are constructing the fields of an object which
+ /// might use a CXXDefaultInitExpr. This stashes away a 'this' value to use
+ /// if we need to evaluate a CXXDefaultInitExpr within the evaluation.
+ class FieldConstructionScope {
+ public:
+ FieldConstructionScope(CodeGenFunction &CGF, llvm::Value *This)
+ : CGF(CGF), OldCXXDefaultInitExprThis(CGF.CXXDefaultInitExprThis) {
+ CGF.CXXDefaultInitExprThis = This;
+ }
+ ~FieldConstructionScope() {
+ CGF.CXXDefaultInitExprThis = OldCXXDefaultInitExprThis;
+ }
+
+ private:
+ CodeGenFunction &CGF;
+ llvm::Value *OldCXXDefaultInitExprThis;
+ };
+
+ /// The scope of a CXXDefaultInitExpr. Within this scope, the value of 'this'
+ /// is overridden to be the object under construction.
+ class CXXDefaultInitExprScope {
+ public:
+ CXXDefaultInitExprScope(CodeGenFunction &CGF)
+ : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue) {
+ CGF.CXXThisValue = CGF.CXXDefaultInitExprThis;
+ }
+ ~CXXDefaultInitExprScope() {
+ CGF.CXXThisValue = OldCXXThisValue;
+ }
+
+ public:
+ CodeGenFunction &CGF;
+ llvm::Value *OldCXXThisValue;
+ };
+
+private:
/// CXXThisDecl - When generating code for a C++ member function,
/// this will hold the implicit 'this' declaration.
ImplicitParamDecl *CXXABIThisDecl;
llvm::Value *CXXABIThisValue;
llvm::Value *CXXThisValue;
+ /// The value of 'this' to use when evaluating CXXDefaultInitExprs within
+ /// this expression.
+ llvm::Value *CXXDefaultInitExprThis;
+
/// CXXStructorImplicitParamDecl - When generating code for a constructor or
/// destructor, this will hold the implicit argument (e.g. VTT).
ImplicitParamDecl *CXXStructorImplicitParamDecl;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 94a507449b..b29ce23fe9 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3054,7 +3054,7 @@ struct BaseAndFieldInfo {
AllToInit.push_back(Init);
// Check whether this initializer makes the field "used".
- if (Init->getInit() && Init->getInit()->HasSideEffects(S.Context))
+ if (Init->getInit()->HasSideEffects(S.Context))
S.UnusedPrivateFields.remove(Init->getAnyMember());
return false;
@@ -3103,16 +3103,18 @@ static bool CollectFieldInitializer(Sema &SemaRef, BaseAndFieldInfo &Info,
// has a brace-or-equal-initializer, the entity is initialized as specified
// in [dcl.init].
if (Field->hasInClassInitializer() && !Info.isImplicitCopyOrMove()) {
+ Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
+ Info.Ctor->getLocation(), Field);
CXXCtorInitializer *Init;
if (Indirect)
Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect,
SourceLocation(),
- SourceLocation(), 0,
+ SourceLocation(), DIE,
SourceLocation());
else
Init = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Field,
SourceLocation(),
- SourceLocation(), 0,
+ SourceLocation(), DIE,
SourceLocation());
return Info.addFieldInitializer(Init);
}
diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp
index 4758718006..1a5f4824d0 100644
--- a/lib/Sema/SemaExceptionSpec.cpp
+++ b/lib/Sema/SemaExceptionSpec.cpp
@@ -1011,7 +1011,6 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ConditionalOperatorClass:
case Expr::CompoundLiteralExprClass:
case Expr::CXXConstCastExprClass:
- case Expr::CXXDefaultArgExprClass:
case Expr::CXXReinterpretCastExprClass:
case Expr::DesignatedInitExprClass:
case Expr::ExprWithCleanupsClass:
@@ -1044,6 +1043,12 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::StmtExprClass:
return CT_Can;
+ case Expr::CXXDefaultArgExprClass:
+ return canThrow(cast(E)->getExpr());
+
+ case Expr::CXXDefaultInitExprClass:
+ return canThrow(cast(E)->getExpr());
+
case Expr::ChooseExprClass:
if (E->isTypeDependent() || E->isValueDependent())
return CT_Dependent;
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 5a5fd26835..0e513992ba 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -293,6 +293,21 @@ void InitListChecker::FillInValueInitForField(unsigned Init, FieldDecl *Field,
InitializedEntity MemberEntity
= InitializedEntity::InitializeMember(Field, &ParentEntity);
if (Init >= NumInits || !ILE->getInit(Init)) {
+ // If there's no explicit initializer but we have a default initializer, use
+ // that. This only happens in C++1y, since classes with default
+ // initializers are not aggregates in C++11.
+ if (Field->hasInClassInitializer()) {
+ Expr *DIE = CXXDefaultInitExpr::Create(SemaRef.Context,
+ ILE->getRBraceLoc(), Field);
+ if (Init < NumInits)
+ ILE->setInit(Init, DIE);
+ else {
+ ILE->updateInit(SemaRef.Context, Init, DIE);
+ RequiresSecondPass = true;
+ }
+ return;
+ }
+
// FIXME: We probably don't need to handle references
// specially here, since value-initialization of references is
// handled in InitializationSequence.
@@ -358,15 +373,24 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
Loc = ILE->getSyntacticForm()->getLocStart();
if (const RecordType *RType = ILE->getType()->getAs()) {
- if (RType->getDecl()->isUnion() &&
- ILE->getInitializedFieldInUnion())
+ const RecordDecl *RDecl = RType->getDecl();
+ if (RDecl->isUnion() && ILE->getInitializedFieldInUnion())
FillInValueInitForField(0, ILE->getInitializedFieldInUnion(),
Entity, ILE, RequiresSecondPass);
- else {
+ else if (RDecl->isUnion() && isa(RDecl) &&
+ cast(RDecl)->hasInClassInitializer()) {
+ for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+ FieldEnd = RDecl->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Field->hasInClassInitializer()) {
+ FillInValueInitForField(0, *Field, Entity, ILE, RequiresSecondPass);
+ break;
+ }
+ }
+ } else {
unsigned Init = 0;
- for (RecordDecl::field_iterator
- Field = RType->getDecl()->field_begin(),
- FieldEnd = RType->getDecl()->field_end();
+ for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+ FieldEnd = RDecl->field_end();
Field != FieldEnd; ++Field) {
if (Field->isUnnamedBitfield())
continue;
@@ -381,7 +405,7 @@ InitListChecker::FillInValueInitializations(const InitializedEntity &Entity,
++Init;
// Only look at the first initialization of a union.
- if (RType->getDecl()->isUnion())
+ if (RDecl->isUnion())
break;
}
}
@@ -1323,8 +1347,23 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
}
if (DeclType->isUnionType() && IList->getNumInits() == 0) {
- // Value-initialize the first named member of the union.
RecordDecl *RD = DeclType->getAs()->getDecl();
+
+ // If there's a default initializer, use it.
+ if (isa(RD) && cast(RD)->hasInClassInitializer()) {
+ if (VerifyOnly)
+ return;
+ for (RecordDecl::field_iterator FieldEnd = RD->field_end();
+ Field != FieldEnd; ++Field) {
+ if (Field->hasInClassInitializer()) {
+ StructuredList->setInitializedFieldInUnion(*Field);
+ // FIXME: Actually build a CXXDefaultInitExpr?
+ return;
+ }
+ }
+ }
+
+ // Value-initialize the first named member of the union.
for (RecordDecl::field_iterator FieldEnd = RD->field_end();
Field != FieldEnd; ++Field) {
if (Field->getDeclName()) {
@@ -1428,7 +1467,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
// Find first (if any) named field and emit warning.
for (RecordDecl::field_iterator it = Field, end = RD->field_end();
it != end; ++it) {
- if (!it->isUnnamedBitfield()) {
+ if (!it->isUnnamedBitfield() && !it->hasInClassInitializer()) {
SemaRef.Diag(IList->getSourceRange().getEnd(),
diag::warn_missing_field_initializers) << it->getName();
break;
@@ -1441,7 +1480,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
!Field->getType()->isIncompleteArrayType()) {
// FIXME: Should check for holes left by designated initializers too.
for (; Field != FieldEnd && !hadError; ++Field) {
- if (!Field->isUnnamedBitfield())
+ if (!Field->isUnnamedBitfield() && !Field->hasInClassInitializer())
CheckValueInitializable(
InitializedEntity::InitializeMember(*Field, &Entity));
}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 55f1587a85..97316f89b3 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1980,6 +1980,17 @@ public:
Param));
}
+ /// \brief Build a new C++11 default-initialization expression.
+ ///
+ /// By default, builds a new default field initialization expression, which
+ /// does not require any semantic analysis. Subclasses may override this
+ /// routine to provide different behavior.
+ ExprResult RebuildCXXDefaultInitExpr(SourceLocation Loc,
+ FieldDecl *Field) {
+ return getSema().Owned(CXXDefaultInitExpr::Create(getSema().Context, Loc,
+ Field));
+ }
+
/// \brief Build a new C++ zero-initialization expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -7260,6 +7271,21 @@ TreeTransform::TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
return getDerived().RebuildCXXDefaultArgExpr(E->getUsedLocation(), Param);
}
+template
+ExprResult
+TreeTransform::TransformCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ FieldDecl *Field
+ = cast_or_null(getDerived().TransformDecl(E->getLocStart(),
+ E->getField()));
+ if (!Field)
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() && Field == E->getField())
+ return SemaRef.Owned(E);
+
+ return getDerived().RebuildCXXDefaultInitExpr(E->getExprLoc(), Field);
+}
+
template
ExprResult
TreeTransform::TransformCXXScalarValueInitExpr(
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index b18114fdcb..c7748b7f6b 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1230,6 +1230,12 @@ void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
E->Loc = ReadSourceLocation(Record, Idx);
}
+void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ VisitExpr(E);
+ E->Field = ReadDeclAs(Record, Idx);
+ E->Loc = ReadSourceLocation(Record, Idx);
+}
+
void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
VisitExpr(E);
E->setTemporary(Reader.ReadCXXTemporary(F, Record, Idx));
@@ -2111,6 +2117,9 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
S = new (Context) CXXDefaultArgExpr(Empty);
break;
}
+ case EXPR_CXX_DEFAULT_INIT:
+ S = new (Context) CXXDefaultInitExpr(Empty);
+ break;
case EXPR_CXX_BIND_TEMPORARY:
S = new (Context) CXXBindTemporaryExpr(Empty);
break;
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 61ddec0fb0..5c8e213384 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1223,6 +1223,13 @@ void ASTStmtWriter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
Code = serialization::EXPR_CXX_DEFAULT_ARG;
}
+void ASTStmtWriter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) {
+ VisitExpr(E);
+ Writer.AddDeclRef(E->getField(), Record);
+ Writer.AddSourceLocation(E->getExprLoc(), Record);
+ Code = serialization::EXPR_CXX_DEFAULT_INIT;
+}
+
void ASTStmtWriter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
VisitExpr(E);
Writer.AddCXXTemporary(E->getTemporary(), Record);
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 92a3a952df..5b6e97d3fb 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -604,6 +604,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
switch (S->getStmtClass()) {
// C++ and ARC stuff we don't support yet.
case Expr::ObjCIndirectCopyRestoreExprClass:
+ case Stmt::CXXDefaultInitExprClass:
case Stmt::CXXDependentScopeMemberExprClass:
case Stmt::CXXPseudoDestructorExprClass:
case Stmt::CXXTryStmtClass:
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
index fef3692609..8767678362 100644
--- a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p1-0x.cpp
@@ -1,4 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y %s -DCXX1Y
// An aggregate is an array or a class...
struct Aggr {
@@ -18,9 +19,6 @@ struct NonAggr1a { // expected-note 2 {{candidate constructor}}
NonAggr1a(int, int); // expected-note {{candidate constructor}}
int k;
};
-// In C++0x, 'user-provided' is only defined for special member functions, so
-// this type is considered to be an aggregate. This is considered to be
-// a language defect.
NonAggr1a na1a = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1a'}}
struct NonAggr1b {
@@ -30,10 +28,15 @@ struct NonAggr1b {
NonAggr1b na1b = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr1b'}}
// no brace-or-equal-initializers for non-static data members, ...
-struct NonAggr2 { // expected-note 3 {{candidate constructor}}
+// Note, this bullet was removed in C++1y.
+struct NonAggr2 {
int m = { 123 };
};
-NonAggr2 na2 = { 42 }; // expected-error {{no matching constructor for initialization of 'NonAggr2'}}
+NonAggr2 na2 = { 42 };
+#ifndef CXX1Y
+// expected-error@-2 {{no matching constructor for initialization of 'NonAggr2'}}
+// expected-note@-6 3 {{candidate constructor}}
+#endif
// no private...
struct NonAggr3 { // expected-note 3 {{candidate constructor}}
diff --git a/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp
new file mode 100644
index 0000000000..d1fbe766d5
--- /dev/null
+++ b/test/CXX/dcl.decl/dcl.init/dcl.init.aggr/p7.cpp
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -std=c++1y %s -verify
+
+// expected-no-diagnostics
+
+struct S { int a; const char *b; int c; int d = b[a]; };
+constexpr S ss = { 1, "asdf" };
+
+static_assert(ss.a == 1, "");
+static_assert(ss.b[2] == 'd', "");
+static_assert(ss.c == 0, "");
+static_assert(ss.d == 's', "");
+
+struct X { int i, j, k = 42; };
+constexpr X a[] = { 1, 2, 3, 4, 5, 6 };
+constexpr X b[2] = { { 1, 2, 3 }, { 4, 5, 6 } };
+
+constexpr bool operator==(X a, X b) {
+ return a.i == b.i && a.j == b.j && a.k == b.k;
+}
+
+static_assert(sizeof(a) == sizeof(b), "");
+static_assert(a[0] == b[0], "");
+static_assert(a[1] == b[1], "");
diff --git a/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
new file mode 100644
index 0000000000..ef78c434e3
--- /dev/null
+++ b/test/CodeGenCXX/cxx1y-initializer-aggregate.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 -std=c++1y %s -triple x86_64-linux-gnu -emit-llvm -o - | FileCheck %s
+
+struct A {
+ int n = 0;
+ const char *p;
+ char k = p[n];
+ int f();
+ int x = f();
+ union {
+ char c;
+ double d = 1.0;
+ };
+};
+
+int f();
+
+union B {
+ int a;
+ int f();
+ int b = f();
+};
+
+A a { .p = "foobar" };
+A b { 4, "bazquux", .x = 42, .c = 9 };
+A c { 1, 0, 'A', f(), { 3 } };
+
+// CHECK: @[[STR_A:.*]] = {{.*}} [7 x i8] c"foobar\00"
+// CHECK: @[[STR_B:.*]] = {{.*}} [8 x i8] c"bazquux\00"
+
+B x;
+B y {};
+B z { 1 };
+// CHECK: @z = global {{.*}} { i32 1 }
+
+// Initialization of 'a':
+
+// CHECK: store i32 0, i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0)
+// CHECK: store i8* {{.*}} @[[STR_A]]{{.*}}, i8** getelementptr inbounds ({{.*}} @a, i32 0, i32 1)
+// CHECK: load i32* getelementptr inbounds ({{.*}} @a, i32 0, i32 0)
+// CHECK: load i8** getelementptr inbounds ({{.*}} @a, i32 0, i32 1)
+// CHECK: getelementptr inbounds i8* %{{.*}}, {{.*}} %{{.*}}
+// CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @a, i32 0, i32 2)
+// CHECK: call i32 @_ZN1A1fEv({{.*}} @a)
+// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @a, i32 0, i32 3)
+// CHECK: call void @{{.*}}C1Ev({{.*}} getelementptr inbounds (%struct.A* @a, i32 0, i32 4))
+
+// Initialization of 'b':
+
+// CHECK: store i32 4, i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0)
+// CHECK: store i8* {{.*}} @[[STR_B]]{{.*}}, i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1)
+// CHECK: load i32* getelementptr inbounds ({{.*}} @b, i32 0, i32 0)
+// CHECK: load i8** getelementptr inbounds ({{.*}} @b, i32 0, i32 1)
+// CHECK: getelementptr inbounds i8* %{{.*}}, {{.*}} %{{.*}}
+// CHECK: store i8 %{{.*}}, i8* getelementptr inbounds ({{.*}} @b, i32 0, i32 2)
+// CHECK-NOT: @_ZN1A1fEv
+// CHECK: store i32 42, i32* getelementptr inbounds ({{.*}}* @b, i32 0, i32 3)
+// CHECK-NOT: C1Ev
+// CHECK: store i8 9, i8* {{.*}} @b, i32 0, i32 4)
+
+// Initialization of 'c':
+
+// CHECK: store i32 1, i32* getelementptr inbounds ({{.*}} @c, i32 0, i32 0)
+// CHECK: store i8* null, i8** getelementptr inbounds ({{.*}} @c, i32 0, i32 1)
+// CHECK-NOT: load
+// CHECK: store i8 65, i8* getelementptr inbounds ({{.*}} @c, i32 0, i32 2)
+// CHECK: call i32 @_Z1fv()
+// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}}* @c, i32 0, i32 3)
+// CHECK-NOT: C1Ev
+// CHECK: store i8 3, i8* {{.*}} @c, i32 0, i32 4)
+
+// CHECK: call void @_ZN1BC1Ev({{.*}} @x)
+
+// CHECK: call i32 @_ZN1B1fEv({{.*}} @y)
+// CHECK: store i32 %{{.*}}, i32* getelementptr inbounds ({{.*}} @y, i32 0, i32 0)
diff --git a/test/SemaCXX/cxx1y-initializer-aggregates.cpp b/test/SemaCXX/cxx1y-initializer-aggregates.cpp
new file mode 100644
index 0000000000..9b542403de
--- /dev/null
+++ b/test/SemaCXX/cxx1y-initializer-aggregates.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -std=c++1y %s -verify
+
+namespace in_class_init {
+ union U { char c; double d = 4.0; };
+ constexpr U u1 = U();
+ constexpr U u2 {};
+ constexpr U u3 { 'x' };
+ static_assert(u1.d == 4.0, "");
+ static_assert(u2.d == 4.0, "");
+ static_assert(u3.c == 'x', "");
+
+ struct A {
+ int n = 5;
+ int m = n * 3;
+ union {
+ char c;
+ double d = 4.0;
+ };
+ };
+ constexpr A a1 {};
+ constexpr A a2 { 8 };
+ constexpr A a3 { 1, 2, { 3 } };
+ constexpr A a4 { 1, 2, { .d = 3.0 } };
+ static_assert(a1.d == 4.0, "");
+ static_assert(a2.m == 24, "");
+ static_assert(a2.d == 4.0, "");
+ static_assert(a3.c == 3, "");
+ static_assert(a3.d == 4.0, ""); // expected-error {{constant expression}} expected-note {{active member 'c'}}
+ static_assert(a4.d == 3.0, "");
+
+ struct B {
+ int n;
+ constexpr int f() { return n * 5; }
+ int m = f();
+ };
+ B b1 {};
+ constexpr B b2 { 2 };
+ B b3 { 1, 2 };
+ static_assert(b2.m == 10, "");
+
+ struct C {
+ int k;
+ union {
+ int l = k; // expected-error {{invalid use of non-static}}
+ };
+ };
+}
+
+namespace nested_aggregate_init {
+ struct A {
+ int n = 5;
+ int b = n * 3;
+ };
+ struct B {
+ constexpr B(int k) : d(1.23), k(k) {}
+ // Within this aggregate, both this object's 'this' and the temporary's
+ // 'this' are used.
+ constexpr int f() const { return A{k}.b; }
+ double d;
+ int k;
+ };
+ static_assert(B(6).f() == 18, "");
+}
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index edcc85b45e..e490b5da3d 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -215,6 +215,7 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
case Stmt::TypeTraitExprClass:
case Stmt::CXXBindTemporaryExprClass:
case Stmt::CXXDefaultArgExprClass:
+ case Stmt::CXXDefaultInitExprClass:
case Stmt::CXXScalarValueInitExprClass:
case Stmt::CXXUuidofExprClass:
case Stmt::ChooseExprClass:
diff --git a/tools/libclang/RecursiveASTVisitor.h b/tools/libclang/RecursiveASTVisitor.h
index 6c9da93b73..dd2c836d9c 100644
--- a/tools/libclang/RecursiveASTVisitor.h
+++ b/tools/libclang/RecursiveASTVisitor.h
@@ -2091,6 +2091,7 @@ DEF_TRAVERSE_STMT(CompoundLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXBindTemporaryExpr, { })
DEF_TRAVERSE_STMT(CXXBoolLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
+DEF_TRAVERSE_STMT(CXXDefaultInitExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
diff --git a/www/cxx_status.html b/www/cxx_status.html
index edd93e7f1f..8a7acc1090 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -457,7 +457,7 @@ ISO/IEC JTC1/SC22/WG21 post-Bristol mailing ships.
Member initializers and aggregates |
N3653 |
- No |
+ SVN |
Clarifying memory allocation |
--
cgit v1.2.3-70-g09d2
From f5ebf9bf1df10ac15ba32a4b24dfe171b7848c58 Mon Sep 17 00:00:00 2001
From: John McCall
Date: Fri, 3 May 2013 07:33:41 +0000
Subject: Correctly emit certain implicit references to 'self' even within a
lambda.
Bug #1 is that CGF's CurFuncDecl was "stuck" at lambda invocation
functions. Fix that by generally improving getNonClosureContext
to look through lambdas and captured statements but only report
code contexts, which is generally what's wanted. Audit uses of
CurFuncDecl and getNonClosureAncestor for correctness.
Bug #2 is that lambdas weren't specially mapping 'self' when inside
an ObjC method. Fix that by removing the requirement for that
and using the normal EmitDeclRefLValue path in LoadObjCSelf.
rdar://13800041
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181000 91177308-0d34-0410-b5e6-96231b3b80d8
---
include/clang/AST/DeclBase.h | 15 +++++----
lib/AST/DeclBase.cpp | 40 ++++++++++++++++-------
lib/CodeGen/CGBlocks.cpp | 25 ++------------
lib/CodeGen/CGCall.cpp | 2 +-
lib/CodeGen/CGClass.cpp | 6 ++--
lib/CodeGen/CGExpr.cpp | 11 +++++++
lib/CodeGen/CGObjC.cpp | 6 ++--
lib/CodeGen/CodeGenFunction.cpp | 13 +++-----
lib/CodeGen/CodeGenFunction.h | 9 ++---
lib/Sema/SemaExprObjC.cpp | 2 +-
test/CodeGenObjC/debug-info-block-captured-self.m | 1 -
test/CodeGenObjC/debug-info-blocks.m | 5 ++-
test/CodeGenObjCXX/lambda-expressions.mm | 22 +++++++++++++
13 files changed, 94 insertions(+), 63 deletions(-)
(limited to 'lib/CodeGen/CGClass.cpp')
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index bceb703060..5d5d45267a 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -372,10 +372,13 @@ public:
return const_cast(this)->getDeclContext();
}
- /// Finds the innermost non-closure context of this declaration.
- /// That is, walk out the DeclContext chain, skipping any blocks.
- DeclContext *getNonClosureContext();
- const DeclContext *getNonClosureContext() const {
+ /// Find the innermost non-closure ancestor of this declaration,
+ /// walking up through blocks, lambdas, etc. If that ancestor is
+ /// not a code context (!isFunctionOrMethod()), returns null.
+ ///
+ /// A declaration may be its own non-closure context.
+ Decl *getNonClosureContext();
+ const Decl *getNonClosureContext() const {
return const_cast(this)->getNonClosureContext();
}
@@ -1114,8 +1117,8 @@ public:
/// \brief Find the nearest non-closure ancestor of this context,
/// i.e. the innermost semantic parent of this context which is not
/// a closure. A context may be its own non-closure ancestor.
- DeclContext *getNonClosureAncestor();
- const DeclContext *getNonClosureAncestor() const {
+ Decl *getNonClosureAncestor();
+ const Decl *getNonClosureAncestor() const {
return const_cast(this)->getNonClosureAncestor();
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 402d83683a..8549b17137 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -704,21 +704,37 @@ void Decl::CheckAccessDeclContext() const {
#endif
}
-DeclContext *Decl::getNonClosureContext() {
- return getDeclContext()->getNonClosureAncestor();
+static Decl::Kind getKind(const Decl *D) { return D->getKind(); }
+static Decl::Kind getKind(const DeclContext *DC) { return DC->getDeclKind(); }
+
+/// Starting at a given context (a Decl or DeclContext), look for a
+/// code context that is not a closure (a lambda, block, etc.).
+template static Decl *getNonClosureContext(T *D) {
+ if (getKind(D) == Decl::CXXMethod) {
+ CXXMethodDecl *MD = cast(D);
+ if (MD->getParent()->isLambda() &&
+ MD->getOverloadedOperator() == OO_Call)
+ return getNonClosureContext(MD->getParent()->getParent());
+ return MD;
+ } else if (FunctionDecl *FD = dyn_cast(D)) {
+ return FD;
+ } else if (ObjCMethodDecl *MD = dyn_cast(D)) {
+ return MD;
+ } else if (BlockDecl *BD = dyn_cast(D)) {
+ return getNonClosureContext(BD->getParent());
+ } else if (CapturedDecl *CD = dyn_cast(D)) {
+ return getNonClosureContext(CD->getParent());
+ } else {
+ return 0;
+ }
}
-DeclContext *DeclContext::getNonClosureAncestor() {
- DeclContext *DC = this;
-
- // This is basically "while (DC->isClosure()) DC = DC->getParent();"
- // except that it's significantly more efficient to cast to a known
- // decl type and call getDeclContext() than to call getParent().
- while (isa(DC))
- DC = cast(DC)->getDeclContext();
+Decl *Decl::getNonClosureContext() {
+ return ::getNonClosureContext(this);
+}
- assert(!DC->isClosure());
- return DC;
+Decl *DeclContext::getNonClosureAncestor() {
+ return ::getNonClosureContext(this);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index dd0ef41750..ded019e64a 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -695,8 +695,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
bool isLambdaConv = blockInfo.getBlockDecl()->isConversionFromLambda();
llvm::Constant *blockFn
= CodeGenFunction(CGM, true).GenerateBlockFunction(CurGD, blockInfo,
- CurFuncDecl, LocalDeclMap,
- isLambdaConv);
+ LocalDeclMap,
+ isLambdaConv);
blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
// If there is nothing to capture, we can emit this as a global block.
@@ -1034,7 +1034,7 @@ CodeGenModule::GetAddrOfGlobalBlock(const BlockExpr *blockExpr,
llvm::DenseMap LocalDeclMap;
blockFn = CodeGenFunction(*this).GenerateBlockFunction(GlobalDecl(),
blockInfo,
- 0, LocalDeclMap,
+ LocalDeclMap,
false);
}
blockFn = llvm::ConstantExpr::getBitCast(blockFn, VoidPtrTy);
@@ -1088,7 +1088,6 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
llvm::Function *
CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
const CGBlockInfo &blockInfo,
- const Decl *outerFnDecl,
const DeclMapTy &ldm,
bool IsLambdaConversionToBlock) {
const BlockDecl *blockDecl = blockInfo.getBlockDecl();
@@ -1148,7 +1147,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
// Begin generating the function.
StartFunction(blockDecl, fnType->getResultType(), fn, fnInfo, args,
blockInfo.getBlockExpr()->getBody()->getLocStart());
- CurFuncDecl = outerFnDecl; // StartFunction sets this to blockDecl
// Okay. Undo some of what StartFunction did.
@@ -1184,23 +1182,6 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD,
CXXThisValue = Builder.CreateLoad(addr, "this");
}
- // LoadObjCSelf() expects there to be an entry for 'self' in LocalDeclMap;
- // appease it.
- if (const ObjCMethodDecl *method
- = dyn_cast_or_null(CurFuncDecl)) {
- const VarDecl *self = method->getSelfDecl();
-
- // There might not be a capture for 'self', but if there is...
- if (blockInfo.Captures.count(self)) {
- const CGBlockInfo::Capture &capture = blockInfo.getCapture(self);
-
- llvm::Value *selfAddr = Builder.CreateStructGEP(BlockPointer,
- capture.getIndex(),
- "block.captured-self");
- LocalDeclMap[self] = selfAddr;
- }
- }
-
// Also force all the constant captures.
for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(),
ce = blockDecl->capture_end(); ci != ce; ++ci) {
diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp
index 4b6fe42fcc..5157dff538 100644
--- a/lib/CodeGen/CGCall.cpp
+++ b/lib/CodeGen/CGCall.cpp
@@ -1196,7 +1196,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
// initialize the return value. TODO: it might be nice to have
// a more general mechanism for this that didn't require synthesized
// return statements.
- if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) {
+ if (const FunctionDecl *FD = dyn_cast_or_null(CurCodeDecl)) {
if (FD->hasImplicitReturnZero()) {
QualType RetTy = FD->getResultType().getUnqualifiedType();
llvm::Type* LLVMTy = CGM.getTypes().ConvertType(RetTy);
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index 2b9a55b2a6..3fd075701d 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -290,7 +290,7 @@ llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD,
return 0;
}
- const CXXRecordDecl *RD = cast(CurFuncDecl)->getParent();
+ const CXXRecordDecl *RD = cast(CurCodeDecl)->getParent();
const CXXRecordDecl *Base = cast(GD.getDecl())->getParent();
llvm::Value *VTT;
@@ -2232,10 +2232,10 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() {
}
void CodeGenFunction::EmitLambdaToBlockPointerBody(FunctionArgList &Args) {
- if (cast(CurFuncDecl)->isVariadic()) {
+ if (cast(CurCodeDecl)->isVariadic()) {
// FIXME: Making this work correctly is nasty because it requires either
// cloning the body of the call operator or making the call operator forward.
- CGM.ErrorUnsupported(CurFuncDecl, "lambda conversion to variadic function");
+ CGM.ErrorUnsupported(CurCodeDecl, "lambda conversion to variadic function");
return;
}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index f426a52bcd..64670c5e81 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -2495,6 +2495,17 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) {
llvm_unreachable("Unhandled member declaration!");
}
+/// Given that we are currently emitting a lambda, emit an l-value for
+/// one of its members.
+LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) {
+ assert(cast(CurCodeDecl)->getParent()->isLambda());
+ assert(cast(CurCodeDecl)->getParent() == Field->getParent());
+ QualType LambdaTagType =
+ getContext().getTagDeclType(Field->getParent());
+ LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue, LambdaTagType);
+ return EmitLValueForField(LambdaLV, Field);
+}
+
LValue CodeGenFunction::EmitLValueForField(LValue base,
const FieldDecl *field) {
if (field->isBitField()) {
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index d0e4cd49dc..713509bf67 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -1401,8 +1401,10 @@ bool CodeGenFunction::IvarTypeWithAggrGCObjects(QualType Ty) {
}
llvm::Value *CodeGenFunction::LoadObjCSelf() {
- const ObjCMethodDecl *OMD = cast(CurFuncDecl);
- return Builder.CreateLoad(LocalDeclMap[OMD->getSelfDecl()], "self");
+ VarDecl *Self = cast(CurFuncDecl)->getSelfDecl();
+ DeclRefExpr DRE(Self, /*is enclosing local*/ (CurFuncDecl != CurCodeDecl),
+ Self->getType(), VK_LValue, SourceLocation());
+ return EmitLoadOfScalar(EmitDeclRefLValue(&DRE));
}
QualType CodeGenFunction::TypeOfSelfObject() {
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 122e95b266..493ee91ec7 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -471,7 +471,8 @@ void CodeGenFunction::EmitOpenCLKernelMetadata(const FunctionDecl *FD,
OpenCLKernelMetadata->addOperand(kernelMDNode);
}
-void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
+void CodeGenFunction::StartFunction(GlobalDecl GD,
+ QualType RetTy,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
@@ -479,7 +480,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
const Decl *D = GD.getDecl();
DidCallStackSave = false;
- CurCodeDecl = CurFuncDecl = D;
+ CurCodeDecl = D;
+ CurFuncDecl = (D ? D->getNonClosureContext() : 0);
FnRetTy = RetTy;
CurFn = Fn;
CurFnInfo = &FnInfo;
@@ -578,12 +580,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
LambdaThisCaptureField);
if (LambdaThisCaptureField) {
// If this lambda captures this, load it.
- QualType LambdaTagType =
- getContext().getTagDeclType(LambdaThisCaptureField->getParent());
- LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue,
- LambdaTagType);
- LValue ThisLValue = EmitLValueForField(LambdaLV,
- LambdaThisCaptureField);
+ LValue ThisLValue = EmitLValueForLambdaField(LambdaThisCaptureField);
CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal();
}
} else {
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 17df1dad3e..7a8a5a6e0b 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -579,8 +579,8 @@ public:
typedef std::pair ComplexPairTy;
CGBuilderTy Builder;
- /// CurFuncDecl - Holds the Decl for the current function or ObjC method.
- /// This excludes BlockDecls.
+ /// CurFuncDecl - Holds the Decl for the current outermost
+ /// non-closure context.
const Decl *CurFuncDecl;
/// CurCodeDecl - This is the inner-most code context, which includes blocks.
const Decl *CurCodeDecl;
@@ -1451,7 +1451,6 @@ public:
llvm::Function *GenerateBlockFunction(GlobalDecl GD,
const CGBlockInfo &Info,
- const Decl *OuterFuncDecl,
const DeclMapTy &ldm,
bool IsLambdaConversionToBlock);
@@ -1482,7 +1481,8 @@ public:
void GenerateCode(GlobalDecl GD, llvm::Function *Fn,
const CGFunctionInfo &FnInfo);
- void StartFunction(GlobalDecl GD, QualType RetTy,
+ void StartFunction(GlobalDecl GD,
+ QualType RetTy,
llvm::Function *Fn,
const CGFunctionInfo &FnInfo,
const FunctionArgList &Args,
@@ -2379,6 +2379,7 @@ public:
llvm::Value *EmitIvarOffset(const ObjCInterfaceDecl *Interface,
const ObjCIvarDecl *Ivar);
LValue EmitLValueForField(LValue Base, const FieldDecl* Field);
+ LValue EmitLValueForLambdaField(const FieldDecl *Field);
/// EmitLValueForFieldInitialization - Like EmitLValueForField, except that
/// if the Field is a reference, this will return the address of the reference
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index fed86eed51..53dc3d8885 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -1334,7 +1334,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
bool Sema::isSelfExpr(Expr *receiver) {
// 'self' is objc 'self' in an objc method only.
ObjCMethodDecl *method =
- dyn_cast(CurContext->getNonClosureAncestor());
+ dyn_cast_or_null(CurContext->getNonClosureAncestor());
if (!method) return false;
receiver = receiver->IgnoreParenLValueCasts();
diff --git a/test/CodeGenObjC/debug-info-block-captured-self.m b/test/CodeGenObjC/debug-info-block-captured-self.m
index 0316013b31..183e91b6ec 100644
--- a/test/CodeGenObjC/debug-info-block-captured-self.m
+++ b/test/CodeGenObjC/debug-info-block-captured-self.m
@@ -59,7 +59,6 @@ typedef enum {
// CHECK: call void @llvm.dbg.declare(metadata !{i8* [[BLOCK_DESC]]}, metadata ![[BDMD:[0-9]+]])
// CHECK: %[[TMP1:.*]] = bitcast
// CHECK-NEXT: store
-// CHECK-NEXT: %[[TMP2:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[TMP1]]
// CHECK: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** {{.*}}}, metadata ![[SELF:.*]])
// make sure we are still in the same function
// CHECK: define {{.*}}__copy_helper_block_
diff --git a/test/CodeGenObjC/debug-info-blocks.m b/test/CodeGenObjC/debug-info-blocks.m
index f50ddf0d8a..3d91c9ea5c 100644
--- a/test/CodeGenObjC/debug-info-blocks.m
+++ b/test/CodeGenObjC/debug-info-blocks.m
@@ -7,11 +7,10 @@
// CHECK: define {{.*}}_block_invoke
// CHECK: %[[BLOCK:.*]] = bitcast i8* %.block_descriptor to <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>*, !dbg
// CHECK-NEXT: store <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA:.*]], align
-// CHECK-NEXT: getelementptr inbounds <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>* %[[BLOCK]], i32 0, i32 5
// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{<{ i8*, i32, i32, i8*, %struct.__block_descriptor*, %0* }>** %[[ALLOCA]]}, metadata ![[SELF:[0-9]+]])
// CHECK-NEXT: call void @llvm.dbg.declare(metadata !{%1** %d}, metadata ![[D:[0-9]+]])
-// CHECK: ![[SELF]] = {{.*}} [ DW_TAG_auto_variable ] [self] [line 52]
-// CHECK: ![[D]] = {{.*}} [d] [line 50]
+// CHECK: ![[SELF]] = {{.*}} [ DW_TAG_auto_variable ] [self] [line 51]
+// CHECK: ![[D]] = {{.*}} [d] [line 49]
typedef unsigned int NSUInteger;
diff --git a/test/CodeGenObjCXX/lambda-expressions.mm b/test/CodeGenObjCXX/lambda-expressions.mm
index 7c1e2e4f57..c73e1727d6 100644
--- a/test/CodeGenObjCXX/lambda-expressions.mm
+++ b/test/CodeGenObjCXX/lambda-expressions.mm
@@ -38,6 +38,28 @@ void f2() { global = []{ return 3; }; }
// ARC: define internal i32 @___Z2f2v_block_invoke
// ARC: call i32 @"_ZZ2f2vENK3$_1clEv
+template void take_lambda(T &&lambda) { lambda(); }
+void take_block(void (^block)()) { block(); }
+
+// rdar://13800041
+@interface A
+- (void) test;
+@end
+@interface B : A @end
+@implementation B
+- (void) test {
+ take_block(^{
+ take_lambda([=]{
+ take_block(^{
+ take_lambda([=] {
+ [super test];
+ });
+ });
+ });
+ });
+}
+@end
+
// ARC: attributes [[NUW]] = { nounwind{{.*}} }
// MRC: attributes [[NUW]] = { nounwind{{.*}} }
--
cgit v1.2.3-70-g09d2