aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-08-07 04:16:51 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-08-07 04:16:51 +0000
commit8ae4ec28451a16a57718286da3e476fc2f495c3f (patch)
tree27a7eeb26c7d5f432b76bedd2c9cf7dbb57db5b4
parentdaa88985ed6d174aeb8c6ddca394f734a73268b7 (diff)
Teach Expr::HasSideEffects about all the Expr types, and fix a bug where it
was mistakenly classifying dynamic_casts which might throw as having no side effects. Switch it from a visitor to a switch, so it is kept up-to-date as future Expr nodes are added. Move it from ExprConstant.cpp to Expr.cpp, since it's not really related to constant expression evaluation. Since we use HasSideEffect to determine whether to emit an unused global with internal linkage, this has the effect of suppressing emission of globals in some cases. I've left many of the Objective-C cases conservatively assuming that the expression has side-effects. I'll leave it to someone with better knowledge of Objective-C than mine to improve them. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161388 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/AST/Expr.cpp215
-rw-r--r--lib/AST/ExprConstant.cpp95
-rw-r--r--test/CodeGenCXX/const-init-cxx11.cpp4
-rw-r--r--test/CodeGenCXX/debug-lambda-expressions.cpp16
-rw-r--r--test/CodeGenCXX/global-init.cpp95
-rw-r--r--test/CodeGenCXX/lambda-expressions.cpp8
-rw-r--r--test/CodeGenObjCXX/encode.mm48
7 files changed, 340 insertions, 141 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index 47b5625b92..faba404b9a 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -2622,6 +2622,221 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
return isEvaluatable(Ctx);
}
+bool Expr::HasSideEffects(const ASTContext &Ctx) const {
+ if (isInstantiationDependent())
+ return true;
+
+ switch (getStmtClass()) {
+ case NoStmtClass:
+ #define ABSTRACT_STMT(Type)
+ #define STMT(Type, Base) case Type##Class:
+ #define EXPR(Type, Base)
+ #include "clang/AST/StmtNodes.inc"
+ llvm_unreachable("unexpected Expr kind");
+
+ case DependentScopeDeclRefExprClass:
+ case CXXUnresolvedConstructExprClass:
+ case CXXDependentScopeMemberExprClass:
+ case UnresolvedLookupExprClass:
+ case UnresolvedMemberExprClass:
+ case PackExpansionExprClass:
+ case SubstNonTypeTemplateParmPackExprClass:
+ llvm_unreachable("shouldn't see dependent / unresolved nodes here");
+
+ case PredefinedExprClass:
+ case IntegerLiteralClass:
+ case FloatingLiteralClass:
+ case ImaginaryLiteralClass:
+ case StringLiteralClass:
+ case CharacterLiteralClass:
+ case OffsetOfExprClass:
+ case ImplicitValueInitExprClass:
+ case UnaryExprOrTypeTraitExprClass:
+ case AddrLabelExprClass:
+ case GNUNullExprClass:
+ case CXXBoolLiteralExprClass:
+ case CXXNullPtrLiteralExprClass:
+ case CXXThisExprClass:
+ case CXXScalarValueInitExprClass:
+ case TypeTraitExprClass:
+ case UnaryTypeTraitExprClass:
+ case BinaryTypeTraitExprClass:
+ case ArrayTypeTraitExprClass:
+ case ExpressionTraitExprClass:
+ case CXXNoexceptExprClass:
+ case SizeOfPackExprClass:
+ case ObjCStringLiteralClass:
+ case ObjCEncodeExprClass:
+ case ObjCBoolLiteralExprClass:
+ case CXXUuidofExprClass:
+ case OpaqueValueExprClass:
+ // These never have a side-effect.
+ return false;
+
+ case CallExprClass:
+ case CompoundAssignOperatorClass:
+ case VAArgExprClass:
+ case AtomicExprClass:
+ case StmtExprClass:
+ case CXXOperatorCallExprClass:
+ case CXXMemberCallExprClass:
+ case UserDefinedLiteralClass:
+ case CXXThrowExprClass:
+ case CXXNewExprClass:
+ case CXXDeleteExprClass:
+ case ExprWithCleanupsClass:
+ case CXXBindTemporaryExprClass:
+ case BlockExprClass:
+ case CUDAKernelCallExprClass:
+ // These always have a side-effect.
+ return true;
+
+ case ParenExprClass:
+ case ArraySubscriptExprClass:
+ case MemberExprClass:
+ case ConditionalOperatorClass:
+ case BinaryConditionalOperatorClass:
+ case ImplicitCastExprClass:
+ case CStyleCastExprClass:
+ case CompoundLiteralExprClass:
+ case ExtVectorElementExprClass:
+ case DesignatedInitExprClass:
+ case ParenListExprClass:
+ case CXXStaticCastExprClass:
+ case CXXReinterpretCastExprClass:
+ case CXXConstCastExprClass:
+ case CXXFunctionalCastExprClass:
+ case CXXPseudoDestructorExprClass:
+ case SubstNonTypeTemplateParmExprClass:
+ case MaterializeTemporaryExprClass:
+ case ShuffleVectorExprClass:
+ case AsTypeExprClass:
+ // These have a side-effect if any subexpression does.
+ break;
+
+ case UnaryOperatorClass: {
+ const UnaryOperator *UO = cast<UnaryOperator>(this);
+ if (UO->isIncrementDecrementOp())
+ return true;
+ if (UO->getOpcode() == UO_Deref && UO->getType().isVolatileQualified())
+ return true;
+ break;
+ }
+
+ case BinaryOperatorClass:
+ if (cast<BinaryOperator>(this)->isAssignmentOp())
+ return true;
+ break;
+
+ case DeclRefExprClass:
+ case ObjCIvarRefExprClass:
+ return getType().isVolatileQualified();
+
+ case InitListExprClass:
+ // FIXME: The children for an InitListExpr doesn't include the array filler.
+ if (const Expr *E = cast<InitListExpr>(this)->getArrayFiller())
+ if (E->HasSideEffects(Ctx))
+ return true;
+ break;
+
+ case GenericSelectionExprClass:
+ return cast<GenericSelectionExpr>(this)->getResultExpr()->
+ HasSideEffects(Ctx);
+
+ case ChooseExprClass:
+ return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->HasSideEffects(Ctx);
+
+ case CXXDefaultArgExprClass:
+ return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx);
+
+ case CXXDynamicCastExprClass: {
+ // A dynamic_cast expression has side-effects if it can throw.
+ const CXXDynamicCastExpr *DCE = cast<CXXDynamicCastExpr>(this);
+ if (DCE->getTypeAsWritten()->isReferenceType() &&
+ DCE->getCastKind() == CK_Dynamic)
+ return true;
+ // Also has side-effects if the subexpression does.
+ break;
+ }
+
+ case CXXTypeidExprClass: {
+ // A typeid expression has side-effects if it can throw.
+ const CXXTypeidExpr *TE = cast<CXXTypeidExpr>(this);
+ if (TE->isTypeOperand())
+ return false;
+ const CXXRecordDecl *RD =
+ TE->getExprOperand()->getType()->getAsCXXRecordDecl();
+ if (!RD || !RD->isPolymorphic() ||
+ !TE->getExprOperand()->
+ Classify(const_cast<ASTContext&>(Ctx)).isGLValue())
+ // Not a glvalue of polymorphic class type: the expression is an
+ // unevaluated operand.
+ return false;
+ // Might throw.
+ return true;
+ }
+
+ case CXXConstructExprClass:
+ case CXXTemporaryObjectExprClass: {
+ const CXXConstructExpr *CE = cast<CXXConstructExpr>(this);
+ if (!CE->isElidable() && !CE->getConstructor()->isTrivial())
+ return true;
+ // An elidable or trivial constructor does not add any side-effects of its
+ // own. Just look at its arguments.
+ break;
+ }
+
+ case LambdaExprClass: {
+ const LambdaExpr *LE = cast<LambdaExpr>(this);
+ for (LambdaExpr::capture_iterator I = LE->capture_begin(),
+ E = LE->capture_end(); I != E; ++I)
+ if (I->getCaptureKind() == LCK_ByCopy)
+ // FIXME: Only has a side-effect if the variable is volatile or if
+ // the copy would invoke a non-trivial copy constructor.
+ return true;
+ return false;
+ }
+
+ case PseudoObjectExprClass: {
+ // Only look for side-effects in the semantic form, and look past
+ // OpaqueValueExpr bindings in that form.
+ const PseudoObjectExpr *PO = cast<PseudoObjectExpr>(this);
+ for (PseudoObjectExpr::const_semantics_iterator I = PO->semantics_begin(),
+ E = PO->semantics_end();
+ I != E; ++I) {
+ const Expr *Subexpr = *I;
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Subexpr))
+ Subexpr = OVE->getSourceExpr();
+ if (Subexpr->HasSideEffects(Ctx))
+ return true;
+ }
+ return false;
+ }
+
+ case ObjCBoxedExprClass:
+ case ObjCArrayLiteralClass:
+ case ObjCDictionaryLiteralClass:
+ case ObjCMessageExprClass:
+ case ObjCSelectorExprClass:
+ case ObjCProtocolExprClass:
+ case ObjCPropertyRefExprClass:
+ case ObjCIsaExprClass:
+ case ObjCIndirectCopyRestoreExprClass:
+ case ObjCSubscriptRefExprClass:
+ case ObjCBridgedCastExprClass:
+ // FIXME: Classify these cases better.
+ return true;
+ }
+
+ // Recurse to children.
+ for (const_child_range SubStmts = children(); SubStmts; ++SubStmts)
+ if (const Stmt *S = *SubStmts)
+ if (cast<Expr>(S)->HasSideEffects(Ctx))
+ return true;
+
+ return false;
+}
+
namespace {
/// \brief Look for a call to a non-trivial function within an expression.
class NonTrivialCallFinder : public EvaluatedExprVisitor<NonTrivialCallFinder>
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 48131f940a..567002cf82 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -2277,91 +2277,6 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
return Success;
}
-namespace {
-class HasSideEffect
- : public ConstStmtVisitor<HasSideEffect, bool> {
- const ASTContext &Ctx;
-public:
-
- HasSideEffect(const ASTContext &C) : Ctx(C) {}
-
- // Unhandled nodes conservatively default to having side effects.
- bool VisitStmt(const Stmt *S) {
- return true;
- }
-
- bool VisitParenExpr(const ParenExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) {
- return Visit(E->getResultExpr());
- }
- bool VisitDeclRefExpr(const DeclRefExpr *E) {
- if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
- return true;
- return false;
- }
- bool VisitObjCIvarRefExpr(const ObjCIvarRefExpr *E) {
- if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
- return true;
- return false;
- }
-
- // We don't want to evaluate BlockExprs multiple times, as they generate
- // a ton of code.
- bool VisitBlockExpr(const BlockExpr *E) { return true; }
- bool VisitPredefinedExpr(const PredefinedExpr *E) { return false; }
- bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E)
- { return Visit(E->getInitializer()); }
- bool VisitMemberExpr(const MemberExpr *E) { return Visit(E->getBase()); }
- bool VisitIntegerLiteral(const IntegerLiteral *E) { return false; }
- bool VisitFloatingLiteral(const FloatingLiteral *E) { return false; }
- bool VisitStringLiteral(const StringLiteral *E) { return false; }
- bool VisitObjCStringLiteral(const ObjCStringLiteral *E) { return false; }
- bool VisitCharacterLiteral(const CharacterLiteral *E) { return false; }
- bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E)
- { return false; }
- bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E)
- { return Visit(E->getLHS()) || Visit(E->getRHS()); }
- bool VisitChooseExpr(const ChooseExpr *E)
- { return Visit(E->getChosenSubExpr(Ctx)); }
- bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E)
- { return Visit(E->getCond()) || Visit(E->getTrueExpr())
- || Visit(E->getFalseExpr()); }
- bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); }
- bool VisitBinAssign(const BinaryOperator *E) { return true; }
- bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; }
- bool VisitBinaryOperator(const BinaryOperator *E)
- { return Visit(E->getLHS()) || Visit(E->getRHS()); }
- bool VisitUnaryPreInc(const UnaryOperator *E) { return true; }
- bool VisitUnaryPostInc(const UnaryOperator *E) { return true; }
- bool VisitUnaryPreDec(const UnaryOperator *E) { return true; }
- bool VisitUnaryPostDec(const UnaryOperator *E) { return true; }
- bool VisitUnaryDeref(const UnaryOperator *E) {
- if (Ctx.getCanonicalType(E->getType()).isVolatileQualified())
- return true;
- return Visit(E->getSubExpr());
- }
- bool VisitUnaryOperator(const UnaryOperator *E) { return Visit(E->getSubExpr()); }
- bool VisitGNUNullExpr(const GNUNullExpr *E) { return false; }
- bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { return false; }
- bool VisitCXXThisExpr(const CXXThisExpr *E) { return false; }
- bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) {
- return false;
- }
-
- // Has side effects if any element does.
- bool VisitInitListExpr(const InitListExpr *E) {
- for (unsigned i = 0, e = E->getNumInits(); i != e; ++i)
- if (Visit(E->getInit(i))) return true;
- if (const Expr *filler = E->getArrayFiller())
- return Visit(filler);
- return false;
- }
-
- bool VisitSizeOfPackExpr(const SizeOfPackExpr *) { return false; }
-};
-
-} // end anonymous namespace
-
//===----------------------------------------------------------------------===//
// Generic Evaluation
//===----------------------------------------------------------------------===//
@@ -4356,9 +4271,9 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
if (TryEvaluateBuiltinObjectSize(E))
return true;
- // If evaluating the argument has side-effects we can't determine
- // the size of the object and lower it to unknown now. CodeGen relies on
- // us to handle all cases where the expression has side-effects.
+ // If evaluating the argument has side-effects, we can't determine the size
+ // of the object, and so we lower it to unknown now. CodeGen relies on us to
+ // handle all cases where the expression has side-effects.
if (E->getArg(0)->HasSideEffects(Info.Ctx)) {
if (E->getArg(1)->EvaluateKnownConstInt(Info.Ctx).getZExtValue() <= 1)
return Success(-1ULL, E);
@@ -6423,10 +6338,6 @@ bool Expr::isEvaluatable(const ASTContext &Ctx) const {
return EvaluateAsRValue(Result, Ctx) && !Result.HasSideEffects;
}
-bool Expr::HasSideEffects(const ASTContext &Ctx) const {
- return HasSideEffect(Ctx).Visit(this);
-}
-
APSInt Expr::EvaluateKnownConstInt(const ASTContext &Ctx) const {
EvalResult EvalResult;
bool Result = EvaluateAsRValue(EvalResult, Ctx);
diff --git a/test/CodeGenCXX/const-init-cxx11.cpp b/test/CodeGenCXX/const-init-cxx11.cpp
index d2504d78cd..db1bb41260 100644
--- a/test/CodeGenCXX/const-init-cxx11.cpp
+++ b/test/CodeGenCXX/const-init-cxx11.cpp
@@ -326,8 +326,8 @@ namespace PR13273 {
S() = default;
};
- // CHECK: @_ZN7PR13273L1sE = {{.*}} zeroinitializer
- const S s {};
+ // CHECK: @_ZN7PR132731sE = {{.*}} zeroinitializer
+ extern const S s {};
}
// Constant initialization tests go before this point,
diff --git a/test/CodeGenCXX/debug-lambda-expressions.cpp b/test/CodeGenCXX/debug-lambda-expressions.cpp
index aed3731e4a..1c823990c1 100644
--- a/test/CodeGenCXX/debug-lambda-expressions.cpp
+++ b/test/CodeGenCXX/debug-lambda-expressions.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 -g | FileCheck %s
auto var = [](int i) { return i+1; };
+void *use = &var;
extern "C" auto cvar = []{};
@@ -13,7 +14,6 @@ int c(int x) { return [&x]{return x;}(); }
struct D { D(); D(const D&); int x; };
int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
-
// Randomness for file. -- 6
// CHECK: [[FILE:.*]] = metadata !{i32 {{.*}}, metadata !{{.*}}debug-lambda-expressions.cpp{{.*}}; [ DW_TAG_file_type ]
@@ -32,8 +32,8 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
// Back to D. -- 24
// CHECK: [[LAM_D:.*]] = metadata !{i32 {{.*}}, metadata [[D_FUNC]], metadata !"", metadata [[FILE]], i32 [[D_LINE]], i64 352, i64 32, i32 0, i32 0, null, metadata [[LAM_D_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
// CHECK: [[LAM_D_ARGS]] = metadata !{metadata [[CAP_D_X:.*]], metadata [[CAP_D_Y:.*]], metadata [[CON_LAM_D:.*]]}
-// CHECK: [[CAP_D_X]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"x", metadata [[FILE]], i32 14, i64 32, i64 32, i64 0, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
-// CHECK: [[CAP_D_Y]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"y", metadata [[FILE]], i32 14, i64 320, i64 32, i64 32, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
+// CHECK: [[CAP_D_X]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"x", metadata [[FILE]], i32 [[D_LINE]], i64 32, i64 32, i64 0, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
+// CHECK: [[CAP_D_Y]] = metadata !{i32 {{.*}}, metadata [[LAM_D]], metadata !"y", metadata [[FILE]], i32 [[D_LINE]], i64 320, i64 32, i64 32, i32 1, metadata {{.*}} ; [ DW_TAG_member ]
// CHECK: [[CON_LAM_D]] = metadata {{.*}}[[LAM_D]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
@@ -58,12 +58,12 @@ int d(int x) { D y[10]; [x,y] { return y[x].x; }(); }
// CHECK: [[CON_LAM_A]] = metadata {{.*}}[[LAM_A]], metadata !"operator()", metadata !"operator()"{{.*}}[ DW_TAG_subprogram ]
-// VAR:
-// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ]
-// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
-// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}}
-
// CVAR:
// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"cvar", metadata !"cvar", metadata !"", metadata [[FILE]], i32 [[CVAR_LINE:.*]], metadata ![[CVAR_T:.*]], i32 0, i32 1, %class.anon.0* @cvar} ; [ DW_TAG_variable ]
// CHECK: [[CVAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[CVAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[CVAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
// CHECK: [[CVAR_ARGS]] = metadata !{metadata !{{.*}}}
+
+// VAR:
+// CHECK: metadata !{i32 {{.*}}, i32 0, null, metadata !"var", metadata !"var", metadata !"", metadata [[FILE]], i32 [[VAR_LINE:.*]], metadata ![[VAR_T:.*]], i32 1, i32 1, %class.anon* @var} ; [ DW_TAG_variable ]
+// CHECK: [[VAR_T]] = metadata !{i32 {{.*}}, null, metadata !"", metadata [[FILE]], i32 [[VAR_LINE]], i64 8, i64 8, i32 0, i32 0, null, metadata ![[VAR_ARGS:.*]], i32 0, null, null} ; [ DW_TAG_class_type ]
+// CHECK: [[VAR_ARGS]] = metadata !{metadata !{{.*}}}
diff --git a/test/CodeGenCXX/global-init.cpp b/test/CodeGenCXX/global-init.cpp
index 8e6ef775ca..da5467ac3f 100644
--- a/test/CodeGenCXX/global-init.cpp
+++ b/test/CodeGenCXX/global-init.cpp
@@ -70,17 +70,17 @@ namespace test3 {
const char *test() { return var; }
}
-namespace test6 {
+namespace test4 {
struct A {
A();
};
extern int foo();
// This needs an initialization function and guard variables.
- // CHECK: load i8* bitcast (i64* @_ZGVN5test61xE
- // CHECK: [[CALL:%.*]] = call i32 @_ZN5test63fooEv
- // CHECK-NEXT: store i32 [[CALL]], i32* @_ZN5test61xE
- // CHECK-NEXT: store i64 1, i64* @_ZGVN5test61xE
+ // CHECK: load i8* bitcast (i64* @_ZGVN5test41xE
+ // CHECK: [[CALL:%.*]] = call i32 @_ZN5test43fooEv
+ // CHECK-NEXT: store i32 [[CALL]], i32* @_ZN5test41xE
+ // CHECK-NEXT: store i64 1, i64* @_ZGVN5test41xE
__attribute__((weak)) int x = foo();
}
@@ -95,14 +95,6 @@ namespace PR5974 {
A* a = &c;
B* b = &c;
}
-// CHECK: define internal void [[TEST1_Z_INIT:@.*]]()
-// CHECK: load i32* @_ZN5test1L1yE
-// CHECK-NEXT: xor
-// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1zE
-// CHECK: define internal void [[TEST1_Y_INIT:@.*]]()
-// CHECK: load i32* @_ZN5test1L1xE
-// CHECK-NEXT: sub
-// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1yE
// PR9570: the indirect field shouldn't crash IR gen.
namespace test5 {
@@ -111,9 +103,86 @@ namespace test5 {
};
}
+namespace std { struct type_info; }
+
+namespace test6 {
+ struct A { virtual ~A(); };
+ struct B : A {};
+ extern A *p;
+
+ // We must emit a dynamic initializer for 'q', because it could throw.
+ B *const q = &dynamic_cast<B&>(*p);
+ // CHECK: call void @__cxa_bad_cast()
+ // CHECK: store {{.*}} @_ZN5test6L1qE
+
+ // We don't need to emit 'r' at all, because it has internal linkage, is
+ // unused, and its initialization has no side-effects.
+ B *const r = dynamic_cast<B*>(p);
+ // CHECK-NOT: call void @__cxa_bad_cast()
+ // CHECK-NOT: store {{.*}} @_ZN5test6L1rE
+
+ // This can throw, so we need to emit it.
+ const std::type_info *const s = &typeid(*p);
+ // CHECK: store {{.*}} @_ZN5test6L1sE
+
+ // This can't throw, so we don't.
+ const std::type_info *const t = &typeid(p);
+ // CHECK-NOT: @_ZN5test6L1tE
+
+ namespace {
+ int a = int();
+ volatile int b = int();
+ int c = a;
+ int d = b;
+ // CHECK-NOT: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1aE
+ // CHECK-NOT: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1bE
+ // CHECK-NOT: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1cE
+ // CHECK: load volatile {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1bE
+ // CHECK: store {{.*}} @_ZN5test6{{[A-Za-z0-9_]*}}1dE
+ }
+}
+
+namespace test7 {
+ struct A { A(); };
+ struct B { ~B(); int n; };
+ struct C { C() = default; C(const C&); };
+ struct D {};
+
+ // CHECK: call void @_ZN5test71AC1Ev({{.*}}@_ZN5test7L1aE)
+ const A a = A();
+
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN5test71BD1Ev{{.*}} @_ZN5test7L2b1E
+ // CHECK: call i32 @__cxa_atexit({{.*}} @_ZN5test71BD1Ev{{.*}} @_ZGRN5test72b2E
+ // CHECK: call void @_ZN5test71BD1Ev(
+ // CHECK: store {{.*}} @_ZN5test7L2b3E
+ const B b1 = B();
+ const B &b2 = B();
+ const int b3 = B().n;
+
+ // CHECK-NOT: @_ZN5test7L2c1E
+ // CHECK: @_ZN5test7L2c2E
+ const C c1 = C(); // elidable copy
+ const C c2 = static_cast<C&&>(C()); // non-elidable copy
+
+ // CHECK-NOT: @_ZN5test7L1dE
+ const D d = D();
+
+ // CHECK: store {{.*}} @_ZN5test71eE
+ int f(), e = f();
+}
+
// At the end of the file, we check that y is initialized before z.
+// CHECK: define internal void [[TEST1_Z_INIT:@.*]]()
+// CHECK: load i32* @_ZN5test1L1yE
+// CHECK-NEXT: xor
+// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1zE
+// CHECK: define internal void [[TEST1_Y_INIT:@.*]]()
+// CHECK: load i32* @_ZN5test1L1xE
+// CHECK-NEXT: sub
+// CHECK-NEXT: store i32 {{.*}}, i32* @_ZN5test1L1yE
+
// CHECK: define internal void @_GLOBAL__I_a() section "__TEXT,__StaticInit,regular,pure_instructions" {
// CHECK: call void [[TEST1_Y_INIT]]
// CHECK: call void [[TEST1_Z_INIT]]
diff --git a/test/CodeGenCXX/lambda-expressions.cpp b/test/CodeGenCXX/lambda-expressions.cpp
index 797cbf43a7..e872cc494b 100644
--- a/test/CodeGenCXX/lambda-expressions.cpp
+++ b/test/CodeGenCXX/lambda-expressions.cpp
@@ -1,7 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10.0.0 -emit-llvm -o - %s -fexceptions -std=c++11 | FileCheck %s
-// CHECK: @var = internal global
-auto var = [](int i) { return i+1; };
+// CHECK-NOT: @unused
+auto unused = [](int i) { return i+1; };
+
+// CHECK: @used = internal global
+auto used = [](int i) { return i+1; };
+void *use = &used;
// CHECK: @cvar = global
extern "C" auto cvar = []{};
diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm
index b2a4b8f013..1b6a241fcf 100644
--- a/test/CodeGenObjCXX/encode.mm
+++ b/test/CodeGenObjCXX/encode.mm
@@ -87,8 +87,8 @@ namespace rdar9357400 {
typedef vector< float, fixed<4> > vector4f;
- // CHECK: @_ZN11rdar9357400L2ggE = internal constant [49 x i8] c"{vector<float, rdar9357400::fixed<4, -1> >=[4f]}\00"
- const char gg[] = @encode(vector4f);
+ // CHECK: @_ZN11rdar93574002ggE = constant [49 x i8] c"{vector<float, rdar9357400::fixed<4, -1> >=[4f]}\00"
+ extern const char gg[] = @encode(vector4f);
}
// rdar://9624314
@@ -97,12 +97,12 @@ namespace rdar9624314 {
struct B3 {};
struct S : B2, B3 {};
- // CHECK: @_ZN11rdar9624314L2ggE = internal constant [6 x i8] c"{S=i}\00"
- const char gg[] = @encode(S);
+ // CHECK: @_ZN11rdar96243142ggE = constant [6 x i8] c"{S=i}\00"
+ extern const char gg[] = @encode(S);
struct S2 { unsigned : 0; int x; unsigned : 0; };
- // CHECK: @_ZN11rdar9624314L2g2E = internal constant [11 x i8] c"{S2=b0ib0}\00"
- const char g2[] = @encode(S2);
+ // CHECK: @_ZN11rdar96243142g2E = constant [11 x i8] c"{S2=b0ib0}\00"
+ extern const char g2[] = @encode(S2);
}
namespace test {
@@ -122,8 +122,8 @@ namespace test {
int y;
};
- // CHECK: @_ZN4testL3ecdE = internal constant [15 x i8] c"{Zoo=^^?ii^^?}\00"
- const char ecd[] = @encode(Zoo);
+ // CHECK: @_ZN4test3ecdE = constant [15 x i8] c"{Zoo=^^?ii^^?}\00"
+ extern const char ecd[] = @encode(Zoo);
}
struct Base1 {
@@ -143,17 +143,17 @@ struct Sub2 : public Sub_with_virt, public Base1, virtual DBase {
float x;
};
-// CHECK: @_ZL2g1 = internal constant [10 x i8] c"{Base1=c}\00"
-const char g1[] = @encode(Base1);
+// CHECK: @g1 = constant [10 x i8] c"{Base1=c}\00"
+extern const char g1[] = @encode(Base1);
-// CHECK: @_ZL2g2 = internal constant [14 x i8] c"{DBase=^^?cd}\00"
-const char g2[] = @encode(DBase);
+// CHECK: @g2 = constant [14 x i8] c"{DBase=^^?cd}\00"
+extern const char g2[] = @encode(DBase);
-// CHECK: @_ZL2g3 = internal constant [26 x i8] c"{Sub_with_virt=^^?q^^?cd}\00"
-const char g3[] = @encode(Sub_with_virt);
+// CHECK: @g3 = constant [26 x i8] c"{Sub_with_virt=^^?q^^?cd}\00"
+extern const char g3[] = @encode(Sub_with_virt);
-// CHECK: @_ZL2g4 = internal constant [19 x i8] c"{Sub2=^^?qcf^^?cd}\00"
-const char g4[] = @encode(Sub2);
+// CHECK: @g4 = constant [19 x i8] c"{Sub2=^^?qcf^^?cd}\00"
+extern const char g4[] = @encode(Sub2);
// http://llvm.org/PR9927
class allocator {
@@ -165,8 +165,8 @@ char* _M_p;
_Alloc_hider _M_dataplus;
};
-// CHECK: @_ZL2g5 = internal constant [32 x i8] c"{basic_string={_Alloc_hider=*}}\00"
-const char g5[] = @encode(basic_string);
+// CHECK: @g5 = constant [32 x i8] c"{basic_string={_Alloc_hider=*}}\00"
+extern const char g5[] = @encode(basic_string);
// PR10990
@@ -175,8 +175,8 @@ class CefBase {
};
class CefBrowser : public virtual CefBase {};
class CefBrowserImpl : public CefBrowser {};
-// CHECK: @_ZL2g6 = internal constant [21 x i8] c"{CefBrowserImpl=^^?}\00"
-const char g6[] = @encode(CefBrowserImpl);
+// CHECK: @g6 = constant [21 x i8] c"{CefBrowserImpl=^^?}\00"
+extern const char g6[] = @encode(CefBrowserImpl);
// PR10990_2
class CefBase2 {
@@ -185,8 +185,8 @@ class CefBase2 {
};
class CefBrowser2 : public virtual CefBase2 {};
class CefBrowserImpl2 : public CefBrowser2 {};
-// CHECK: @_ZL2g7 = internal constant [26 x i8] c"{CefBrowserImpl2=^^?^^?i}\00"
-const char g7[] = @encode(CefBrowserImpl2);
+// CHECK: @g7 = constant [26 x i8] c"{CefBrowserImpl2=^^?^^?i}\00"
+extern const char g7[] = @encode(CefBrowserImpl2);
// <rdar://problem/11324167>
struct Empty {};
@@ -199,5 +199,5 @@ struct Y : Empty {
X vec;
};
-// CHECK: @_ZL2g8 = internal constant [14 x i8] c"{Y={X=[10i]}}\00"
-const char g8[] = @encode(Y);
+// CHECK: @g8 = constant [14 x i8] c"{Y={X=[10i]}}\00"
+extern const char g8[] = @encode(Y);