Change EmitConstantExpr to allow failure.
IRgen no longer relies on isConstantInitializer, instead we just try to emit the constant. If that fails then in C we emit an error unsupported (this occurs when Sema accepted something that it doesn't know how to fold, and IRgen doesn't know how to emit) and in C++ we emit a guarded initializer. This ends up handling a few more cases, because IRgen was actually able to emit some of the constants Sema accepts but can't Evaluate(). For example, PR3398. llvm-svn: 64780
This commit is contained in:
parent
3d926cbf79
commit
38ad1e6138
|
@ -88,12 +88,17 @@ CodeGenFunction::GenerateStaticBlockVarDecl(const VarDecl &D,
|
||||||
if ((D.getInit() == 0) || NoInit) {
|
if ((D.getInit() == 0) || NoInit) {
|
||||||
Init = llvm::Constant::getNullValue(LTy);
|
Init = llvm::Constant::getNullValue(LTy);
|
||||||
} else {
|
} else {
|
||||||
if (D.getInit()->isConstantInitializer(getContext()))
|
Init = CGM.EmitConstantExpr(D.getInit(), this);
|
||||||
Init = CGM.EmitConstantExpr(D.getInit(), this);
|
|
||||||
else {
|
// If constant emission failed, then this should be a C++ static
|
||||||
assert(getContext().getLangOptions().CPlusPlus &&
|
// initializer.
|
||||||
"only C++ supports non-constant static initializers!");
|
if (!Init) {
|
||||||
return GenerateStaticCXXBlockVarDecl(D);
|
if (!getContext().getLangOptions().CPlusPlus) {
|
||||||
|
CGM.ErrorUnsupported(D.getInit(), "constant l-value expression");
|
||||||
|
Init = llvm::Constant::getNullValue(LTy);
|
||||||
|
} else {
|
||||||
|
return GenerateStaticCXXBlockVarDecl(D);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,7 +61,6 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Constant *C = Visit(E->getSubExpr());
|
llvm::Constant *C = Visit(E->getSubExpr());
|
||||||
|
|
||||||
return EmitConversion(C, E->getSubExpr()->getType(), E->getType());
|
return EmitConversion(C, E->getSubExpr()->getType(), E->getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,6 +89,8 @@ public:
|
||||||
bool RewriteType = false;
|
bool RewriteType = false;
|
||||||
for (; i < NumInitableElts; ++i) {
|
for (; i < NumInitableElts; ++i) {
|
||||||
llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(i), CGF);
|
llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(i), CGF);
|
||||||
|
if (!C)
|
||||||
|
return 0;
|
||||||
RewriteType |= (C->getType() != ElemTy);
|
RewriteType |= (C->getType() != ElemTy);
|
||||||
Elts.push_back(C);
|
Elts.push_back(C);
|
||||||
}
|
}
|
||||||
|
@ -114,6 +115,9 @@ public:
|
||||||
FieldDecl* Field, Expr* E) {
|
FieldDecl* Field, Expr* E) {
|
||||||
// Calculate the value to insert
|
// Calculate the value to insert
|
||||||
llvm::Constant *C = CGM.EmitConstantExpr(E, CGF);
|
llvm::Constant *C = CGM.EmitConstantExpr(E, CGF);
|
||||||
|
if (!C)
|
||||||
|
return;
|
||||||
|
|
||||||
llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C);
|
llvm::ConstantInt *CI = dyn_cast<llvm::ConstantInt>(C);
|
||||||
if (!CI) {
|
if (!CI) {
|
||||||
CGM.ErrorUnsupported(E, "bitfield initialization");
|
CGM.ErrorUnsupported(E, "bitfield initialization");
|
||||||
|
@ -198,6 +202,7 @@ public:
|
||||||
} else {
|
} else {
|
||||||
unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(*Field);
|
unsigned FieldNo = CGM.getTypes().getLLVMFieldNo(*Field);
|
||||||
llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(EltNo), CGF);
|
llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(EltNo), CGF);
|
||||||
|
if (!C) return 0;
|
||||||
RewriteType |= (C->getType() != Elts[FieldNo]->getType());
|
RewriteType |= (C->getType() != Elts[FieldNo]->getType());
|
||||||
Elts[FieldNo] = C;
|
Elts[FieldNo] = C;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +222,9 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Constant *EmitUnion(llvm::Constant *C, const llvm::Type *Ty) {
|
llvm::Constant *EmitUnion(llvm::Constant *C, const llvm::Type *Ty) {
|
||||||
|
if (!C)
|
||||||
|
return 0;
|
||||||
|
|
||||||
// Build a struct with the union sub-element as the first member,
|
// Build a struct with the union sub-element as the first member,
|
||||||
// and padded to the appropriate size
|
// and padded to the appropriate size
|
||||||
std::vector<llvm::Constant*> Elts;
|
std::vector<llvm::Constant*> Elts;
|
||||||
|
@ -289,6 +297,8 @@ public:
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
for (; i < NumInitableElts; ++i) {
|
for (; i < NumInitableElts; ++i) {
|
||||||
llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(i), CGF);
|
llvm::Constant *C = CGM.EmitConstantExpr(ILE->getInit(i), CGF);
|
||||||
|
if (!C)
|
||||||
|
return 0;
|
||||||
Elts.push_back(C);
|
Elts.push_back(C);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,6 +412,9 @@ public:
|
||||||
|
|
||||||
llvm::Constant *EmitConversion(llvm::Constant *Src, QualType SrcType,
|
llvm::Constant *EmitConversion(llvm::Constant *Src, QualType SrcType,
|
||||||
QualType DstType) {
|
QualType DstType) {
|
||||||
|
if (!Src)
|
||||||
|
return 0;
|
||||||
|
|
||||||
SrcType = CGM.getContext().getCanonicalType(SrcType);
|
SrcType = CGM.getContext().getCanonicalType(SrcType);
|
||||||
DstType = CGM.getContext().getCanonicalType(DstType);
|
DstType = CGM.getContext().getCanonicalType(DstType);
|
||||||
if (SrcType == DstType) return Src;
|
if (SrcType == DstType) return Src;
|
||||||
|
@ -488,9 +501,12 @@ public:
|
||||||
// to be the only use of the variable, so we just generate it here.
|
// to be the only use of the variable, so we just generate it here.
|
||||||
CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
|
CompoundLiteralExpr *CLE = cast<CompoundLiteralExpr>(E);
|
||||||
llvm::Constant* C = Visit(CLE->getInitializer());
|
llvm::Constant* C = Visit(CLE->getInitializer());
|
||||||
C = new llvm::GlobalVariable(C->getType(),E->getType().isConstQualified(),
|
// FIXME: "Leaked" on failure.
|
||||||
llvm::GlobalValue::InternalLinkage,
|
if (C)
|
||||||
C, ".compoundliteral", &CGM.getModule());
|
C = new llvm::GlobalVariable(C->getType(),
|
||||||
|
E->getType().isConstQualified(),
|
||||||
|
llvm::GlobalValue::InternalLinkage,
|
||||||
|
C, ".compoundliteral", &CGM.getModule());
|
||||||
return C;
|
return C;
|
||||||
}
|
}
|
||||||
case Expr::DeclRefExprClass:
|
case Expr::DeclRefExprClass:
|
||||||
|
@ -515,6 +531,8 @@ public:
|
||||||
Base = Visit(ME->getBase());
|
Base = Visit(ME->getBase());
|
||||||
else
|
else
|
||||||
Base = EmitLValue(ME->getBase());
|
Base = EmitLValue(ME->getBase());
|
||||||
|
if (!Base)
|
||||||
|
return 0;
|
||||||
|
|
||||||
FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
|
FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl());
|
||||||
// FIXME: Handle other kinds of member expressions.
|
// FIXME: Handle other kinds of member expressions.
|
||||||
|
@ -528,10 +546,13 @@ public:
|
||||||
}
|
}
|
||||||
case Expr::ArraySubscriptExprClass: {
|
case Expr::ArraySubscriptExprClass: {
|
||||||
ArraySubscriptExpr* ASExpr = cast<ArraySubscriptExpr>(E);
|
ArraySubscriptExpr* ASExpr = cast<ArraySubscriptExpr>(E);
|
||||||
llvm::Constant *Base = Visit(ASExpr->getBase());
|
|
||||||
llvm::Constant *Index = Visit(ASExpr->getIdx());
|
|
||||||
assert(!ASExpr->getBase()->getType()->isVectorType() &&
|
assert(!ASExpr->getBase()->getType()->isVectorType() &&
|
||||||
"Taking the address of a vector component is illegal!");
|
"Taking the address of a vector component is illegal!");
|
||||||
|
|
||||||
|
llvm::Constant *Base = Visit(ASExpr->getBase());
|
||||||
|
llvm::Constant *Index = Visit(ASExpr->getIdx());
|
||||||
|
if (!Base || !Index)
|
||||||
|
return 0;
|
||||||
return llvm::ConstantExpr::getGetElementPtr(Base, &Index, 1);
|
return llvm::ConstantExpr::getGetElementPtr(Base, &Index, 1);
|
||||||
}
|
}
|
||||||
case Expr::StringLiteralClass:
|
case Expr::StringLiteralClass:
|
||||||
|
@ -594,9 +615,8 @@ public:
|
||||||
return CGM.GetAddrOfConstantCFString(S);
|
return CGM.GetAddrOfConstantCFString(S);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CGM.ErrorUnsupported(E, "constant l-value expression");
|
|
||||||
llvm::Type *Ty = llvm::PointerType::getUnqual(ConvertType(E->getType()));
|
return 0;
|
||||||
return llvm::UndefValue::get(Ty);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -604,8 +624,6 @@ public:
|
||||||
|
|
||||||
llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
||||||
CodeGenFunction *CGF) {
|
CodeGenFunction *CGF) {
|
||||||
QualType type = Context.getCanonicalType(E->getType());
|
|
||||||
|
|
||||||
Expr::EvalResult Result;
|
Expr::EvalResult Result;
|
||||||
|
|
||||||
if (E->Evaluate(Result, Context)) {
|
if (E->Evaluate(Result, Context)) {
|
||||||
|
@ -613,8 +631,8 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
||||||
"Constant expr should not have any side effects!");
|
"Constant expr should not have any side effects!");
|
||||||
switch (Result.Val.getKind()) {
|
switch (Result.Val.getKind()) {
|
||||||
case APValue::Uninitialized:
|
case APValue::Uninitialized:
|
||||||
assert(0 && "Constant expressions should be uninitialized.");
|
assert(0 && "Constant expressions should be initialized.");
|
||||||
return llvm::UndefValue::get(getTypes().ConvertType(type));
|
return 0;
|
||||||
case APValue::LValue: {
|
case APValue::LValue: {
|
||||||
llvm::Constant *Offset =
|
llvm::Constant *Offset =
|
||||||
llvm::ConstantInt::get(llvm::Type::Int64Ty,
|
llvm::ConstantInt::get(llvm::Type::Int64Ty,
|
||||||
|
@ -637,7 +655,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
||||||
}
|
}
|
||||||
|
|
||||||
return llvm::ConstantExpr::getIntToPtr(Offset,
|
return llvm::ConstantExpr::getIntToPtr(Offset,
|
||||||
getTypes().ConvertType(type));
|
getTypes().ConvertType(E->getType()));
|
||||||
}
|
}
|
||||||
case APValue::Int: {
|
case APValue::Int: {
|
||||||
llvm::Constant *C = llvm::ConstantInt::get(Result.Val.getInt());
|
llvm::Constant *C = llvm::ConstantInt::get(Result.Val.getInt());
|
||||||
|
@ -683,7 +701,7 @@ llvm::Constant *CodeGenModule::EmitConstantExpr(const Expr *E,
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
|
llvm::Constant* C = ConstExprEmitter(*this, CGF).Visit(const_cast<Expr*>(E));
|
||||||
if (C->getType() == llvm::Type::Int1Ty) {
|
if (C && C->getType() == llvm::Type::Int1Ty) {
|
||||||
const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
|
const llvm::Type *BoolTy = getTypes().ConvertTypeForMem(E->getType());
|
||||||
C = llvm::ConstantExpr::getZExt(C, BoolTy);
|
C = llvm::ConstantExpr::getZExt(C, BoolTy);
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,12 @@ public:
|
||||||
const std::string &Name);
|
const std::string &Name);
|
||||||
|
|
||||||
void UpdateCompletedType(const TagDecl *D);
|
void UpdateCompletedType(const TagDecl *D);
|
||||||
|
|
||||||
|
/// EmitConstantExpr - Try to emit the given expression as a
|
||||||
|
/// constant; returns 0 if the expression cannot be emitted as a
|
||||||
|
/// constant.
|
||||||
llvm::Constant *EmitConstantExpr(const Expr *E, CodeGenFunction *CGF = 0);
|
llvm::Constant *EmitConstantExpr(const Expr *E, CodeGenFunction *CGF = 0);
|
||||||
|
|
||||||
llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
|
llvm::Constant *EmitAnnotateAttr(llvm::GlobalValue *GV,
|
||||||
const AnnotateAttr *AA, unsigned LineNo);
|
const AnnotateAttr *AA, unsigned LineNo);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// RUN: clang -emit-llvm < %s | grep "g.b = internal global i8. getelementptr"
|
// RUN: clang -arch i386 -emit-llvm -o %t %s &&
|
||||||
|
// RUN: grep "g.b = internal global i8. getelementptr" %t &&
|
||||||
|
|
||||||
struct AStruct {
|
struct AStruct {
|
||||||
int i;
|
int i;
|
||||||
|
@ -24,3 +25,7 @@ struct s { void *p; };
|
||||||
void foo(void) {
|
void foo(void) {
|
||||||
static struct s var = {((void*)&((char*)0)[0])};
|
static struct s var = {((void*)&((char*)0)[0])};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RUN: grep "f1.l0 = internal global i32 ptrtoint (i32 ()\* @f1 to i32)" %t
|
||||||
|
int f1(void) { static int l0 = (unsigned) f1; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue