diff options
-rw-r--r-- | lib/AST/Expr.cpp | 215 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 95 | ||||
-rw-r--r-- | test/CodeGenCXX/const-init-cxx11.cpp | 4 | ||||
-rw-r--r-- | test/CodeGenCXX/debug-lambda-expressions.cpp | 16 | ||||
-rw-r--r-- | test/CodeGenCXX/global-init.cpp | 95 | ||||
-rw-r--r-- | test/CodeGenCXX/lambda-expressions.cpp | 8 | ||||
-rw-r--r-- | test/CodeGenObjCXX/encode.mm | 48 |
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); |