]> granicus.if.org Git - clang/commitdiff
Implement the initial part of C++0x [expr.const]p2, which specifies
authorDouglas Gregor <dgregor@apple.com>
Tue, 24 May 2011 16:02:01 +0000 (16:02 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 24 May 2011 16:02:01 +0000 (16:02 +0000)
that the unevaluated subexpressions of &&, ||, and ? : are not
considered when determining whether the expression is a constant
expression. Also, turn the "used in its own initializer" warning into
a runtime-behavior warning, so that it doesn't fire when a variable is
used as part of an unevaluated subexpression of its own initializer.

Fixes PR9999.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131968 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ExprConstant.cpp
lib/Sema/SemaDecl.cpp
test/CXX/expr/expr.const/p2-0x.cpp [new file with mode: 0644]

index 1126289aee496169d9ea1a66f2bc3d6afaec7a0c..1206fe7fb33d2e67473da0f212347083c65b55e0 100644 (file)
@@ -2957,6 +2957,21 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
     case BO_LAnd:
     case BO_LOr: {
       ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+
+      // C++0x [expr.const]p2:
+      //   [...] subexpressions of logical AND (5.14), logical OR
+      //   (5.15), and condi- tional (5.16) operations that are not
+      //   evaluated are not considered.
+      if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) {
+        if (Exp->getOpcode() == BO_LAnd && 
+            Exp->getLHS()->EvaluateAsInt(Ctx) == 0)
+          return LHSResult;
+
+        if (Exp->getOpcode() == BO_LOr &&
+            Exp->getLHS()->EvaluateAsInt(Ctx) != 0)
+          return LHSResult;
+      }
+
       ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
       if (LHSResult.Val == 0 && RHSResult.Val == 1) {
         // Rare case where the RHS has a comma "side-effect"; we need
@@ -3015,10 +3030,22 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
         return NoDiag();
       }
     ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
-    ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
-    ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
     if (CondResult.Val == 2)
       return CondResult;
+
+    // C++0x [expr.const]p2:
+    //   subexpressions of [...] conditional (5.16) operations that
+    //   are not evaluated are not considered
+    bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x
+      ? Exp->getCond()->EvaluateAsInt(Ctx) != 0
+      : false;
+    ICEDiag TrueResult = NoDiag();
+    if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch)
+      TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
+    ICEDiag FalseResult = NoDiag();
+    if (!Ctx.getLangOptions().CPlusPlus0x || !TrueBranch)
+      FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+
     if (TrueResult.Val == 2)
       return TrueResult;
     if (FalseResult.Val == 2)
index 3965a45171c4797dc3319285cebdd163a90ac230..7bcd205b2237bca232b102bed840195a0ac53214 100644 (file)
@@ -5149,9 +5149,11 @@ namespace {
       if (OrigDecl != ReferenceDecl) return;
       LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName,
                           Sema::NotForRedeclaration);
-      S.Diag(SubExpr->getLocStart(), diag::warn_uninit_self_reference_in_init)
-        << Result.getLookupName() << OrigDecl->getLocation()
-        << SubExpr->getSourceRange();
+      S.DiagRuntimeBehavior(SubExpr->getLocStart(), SubExpr,
+                            S.PDiag(diag::warn_uninit_self_reference_in_init)
+                              << Result.getLookupName() 
+                              << OrigDecl->getLocation()
+                              << SubExpr->getSourceRange());
     }
   };
 }
diff --git a/test/CXX/expr/expr.const/p2-0x.cpp b/test/CXX/expr/expr.const/p2-0x.cpp
new file mode 100644 (file)
index 0000000..1b38cf1
--- /dev/null
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++0x -verify %s
+
+// PR9999
+template<bool v>
+class bitWidthHolding {
+public:
+  static const
+  unsigned int width = (v == 0 ? 0 : bitWidthHolding<(v >> 1)>::width + 1);
+};
+
+static const int width=bitWidthHolding<255>::width;
+
+template<bool b>
+struct always_false {
+  static const bool value = false;
+};
+
+template<bool b>
+struct and_or {
+  static const bool and_value = b && and_or<always_false<b>::value>::and_value;
+  static const bool or_value = !b || and_or<always_false<b>::value>::or_value;
+};
+
+static const bool and_value = and_or<true>::and_value;
+static const bool or_value = and_or<true>::or_value;