[cfe-commits] r161388 - in /cfe/trunk: lib/AST/Expr.cpp lib/AST/ExprConstant.cpp test/CodeGenCXX/const-init-cxx11.cpp test/CodeGenCXX/debug-lambda-expressions.cpp test/CodeGenCXX/global-init.cpp test/CodeGenCXX/lambda-expressions.cpp test/CodeGenObjCXX/encode.mm

Richard Smith richard-llvm at metafoo.co.uk
Mon Aug 6 21:16:51 PDT 2012


Author: rsmith
Date: Mon Aug  6 23:16:51 2012
New Revision: 161388

URL: http://llvm.org/viewvc/llvm-project?rev=161388&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
    cfe/trunk/test/CodeGenCXX/debug-lambda-expressions.cpp
    cfe/trunk/test/CodeGenCXX/global-init.cpp
    cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp
    cfe/trunk/test/CodeGenObjCXX/encode.mm

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=161388&r1=161387&r2=161388&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Mon Aug  6 23:16:51 2012
@@ -2622,6 +2622,221 @@
   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>

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=161388&r1=161387&r2=161388&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Aug  6 23:16:51 2012
@@ -2277,91 +2277,6 @@
   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 @@
     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 @@
   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);

Modified: cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp?rev=161388&r1=161387&r2=161388&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/const-init-cxx11.cpp Mon Aug  6 23:16:51 2012
@@ -326,8 +326,8 @@
     S() = default;
   };
 
-  // CHECK: @_ZN7PR13273L1sE = {{.*}} zeroinitializer
-  const S s {};
+  // CHECK: @_ZN7PR132731sE = {{.*}} zeroinitializer
+  extern const S s {};
 }
 
 // Constant initialization tests go before this point,

Modified: cfe/trunk/test/CodeGenCXX/debug-lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-lambda-expressions.cpp?rev=161388&r1=161387&r2=161388&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/debug-lambda-expressions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/debug-lambda-expressions.cpp Mon Aug  6 23:16:51 2012
@@ -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 @@
 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 @@
 // 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 @@
 // 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 !{{.*}}}

Modified: cfe/trunk/test/CodeGenCXX/global-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/global-init.cpp?rev=161388&r1=161387&r2=161388&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/global-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/global-init.cpp Mon Aug  6 23:16:51 2012
@@ -70,17 +70,17 @@
   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 @@
   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 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]]

Modified: cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp?rev=161388&r1=161387&r2=161388&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/lambda-expressions.cpp Mon Aug  6 23:16:51 2012
@@ -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 = []{};

Modified: cfe/trunk/test/CodeGenObjCXX/encode.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/encode.mm?rev=161388&r1=161387&r2=161388&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/encode.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/encode.mm Mon Aug  6 23:16:51 2012
@@ -87,8 +87,8 @@
 
   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 @@
   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 @@
    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 @@
   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 @@
 _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 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 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 @@
   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);





More information about the cfe-commits mailing list