r180022 - C++1y constexpr extensions, round 1: Allow most forms of declaration and

Richard Smith richard-llvm at metafoo.co.uk
Mon Apr 22 08:31:51 PDT 2013


Author: rsmith
Date: Mon Apr 22 10:31:51 2013
New Revision: 180022

URL: http://llvm.org/viewvc/llvm-project?rev=180022&view=rev
Log:
C++1y constexpr extensions, round 1: Allow most forms of declaration and
statement in constexpr functions. Everything which doesn't require variable
mutation is also allowed as an extension in C++11. 'void' becomes a literal
type to support constexpr functions which return 'void'.

Added:
    cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
Modified:
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/test/CXX/basic/basic.types/p10.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
    cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
    cfe/trunk/test/CXX/except/except.spec/p1.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Apr 22 10:31:51 2013
@@ -1443,8 +1443,8 @@ public:
   }
 
   /// isLiteralType - Return true if this is a literal type
-  /// (C++0x [basic.types]p10)
-  bool isLiteralType() const;
+  /// (C++11 [basic.types]p10)
+  bool isLiteralType(ASTContext &Ctx) const;
 
   /// \brief Test if this type is a standard-layout type.
   /// (C++0x [basic.type]p9)

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Mon Apr 22 10:31:51 2013
@@ -26,6 +26,8 @@ def note_constexpr_lshift_discards : Not
 def note_constexpr_invalid_function : Note<
   "%select{non-constexpr|undefined}0 %select{function|constructor}1 %2 cannot "
   "be used in a constant expression">;
+def note_constexpr_no_return : Note<
+  "control reached end of constexpr function">;
 def note_constexpr_virtual_call : Note<
   "cannot evaluate virtual function call in a constant expression">;
 def note_constexpr_virtual_base : Note<

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Apr 22 10:31:51 2013
@@ -1593,20 +1593,54 @@ def err_constexpr_non_literal_param : Er
   "not a literal type">;
 def err_constexpr_body_invalid_stmt : Error<
   "statement not allowed in constexpr %select{function|constructor}0">;
-def err_constexpr_type_definition : Error<
-  "types cannot be defined in a constexpr %select{function|constructor}0">;
+def ext_constexpr_body_invalid_stmt : ExtWarn<
+  "use of this statement in a constexpr %select{function|constructor}0 "
+  "is a C++1y extension">, InGroup<CXX1y>;
+def warn_cxx11_compat_constexpr_body_invalid_stmt : Warning<
+  "use of this statement in a constexpr %select{function|constructor}0 "
+  "is incompatible with C++ standards before C++1y">,
+  InGroup<CXXPre1yCompat>, DefaultIgnore;
+def ext_constexpr_type_definition : ExtWarn<
+  "type definition in a constexpr %select{function|constructor}0 "
+  "is a C++1y extension">, InGroup<CXX1y>;
+def warn_cxx11_compat_constexpr_type_definition : Warning<
+  "type definition in a constexpr %select{function|constructor}0 "
+  "is incompatible with C++ standards before C++1y">,
+  InGroup<CXXPre1yCompat>, DefaultIgnore;
 def err_constexpr_vla : Error<
   "variably-modified type %0 cannot be used in a constexpr "
   "%select{function|constructor}1">;
-def err_constexpr_var_declaration : Error<
-  "variables cannot be declared in a constexpr %select{function|constructor}0">;
+def ext_constexpr_local_var : ExtWarn<
+  "variable declaration in a constexpr %select{function|constructor}0 "
+  "is a C++1y extension">, InGroup<CXX1y>;
+def warn_cxx11_compat_constexpr_local_var : Warning<
+  "variable declaration in a constexpr %select{function|constructor}0 "
+  "is incompatible with C++ standards before C++1y">,
+  InGroup<CXXPre1yCompat>, DefaultIgnore;
+def err_constexpr_local_var_static : Error<
+  "%select{static|thread_local}1 variable not permitted in a constexpr "
+  "%select{function|constructor}0">;
+def err_constexpr_local_var_non_literal_type : Error<
+  "variable of non-literal type %1 cannot be defined in a constexpr "
+  "%select{function|constructor}0">;
+def err_constexpr_local_var_no_init : Error<
+  "variables defined in a constexpr %select{function|constructor}0 must be "
+  "initialized">;
 def ext_constexpr_function_never_constant_expr : ExtWarn<
   "constexpr %select{function|constructor}0 never produces a "
   "constant expression">, InGroup<DiagGroup<"invalid-constexpr">>, DefaultError;
 def err_constexpr_body_no_return : Error<
   "no return statement in constexpr function">;
-def err_constexpr_body_multiple_return : Error<
-  "multiple return statements in constexpr function">;
+def warn_cxx11_compat_constexpr_body_no_return : Warning<
+  "constexpr function with no return statements is incompatible with C++ "
+  "standards before C++1y">, InGroup<CXXPre1yCompat>, DefaultIgnore;
+def ext_constexpr_body_multiple_return : ExtWarn<
+  "multiple return statements in constexpr function is a C++1y extension">,
+  InGroup<CXX1y>;
+def warn_cxx11_compat_constexpr_body_multiple_return : Warning<
+  "multiple return statements in constexpr function "
+  "is incompatible with C++ standards before C++1y">,
+  InGroup<CXXPre1yCompat>, DefaultIgnore;
 def note_constexpr_body_previous_return : Note<
   "previous return statement is here">;
 def err_constexpr_function_try_block : Error<

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Apr 22 10:31:51 2013
@@ -186,7 +186,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier
       data().IsStandardLayout = false;
 
     // Record if this base is the first non-literal field or base.
-    if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType())
+    if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType(C))
       data().HasNonLiteralTypeFieldsOrBases = true;
     
     // Now go through all virtual bases of this base and add them.
@@ -676,7 +676,7 @@ void CXXRecordDecl::addedMember(Decl *D)
     }
 
     // Record if this field is the first non-literal or volatile field or base.
-    if (!T->isLiteralType() || T.isVolatileQualified())
+    if (!T->isLiteralType(Context) || T.isVolatileQualified())
       data().HasNonLiteralTypeFieldsOrBases = true;
 
     if (Field->hasInClassInitializer()) {
@@ -845,7 +845,7 @@ void CXXRecordDecl::addedMember(Decl *D)
       }
     } else {
       // Base element type of field is a non-class type.
-      if (!T->isLiteralType() ||
+      if (!T->isLiteralType(Context) ||
           (!Field->hasInClassInitializer() && !isUnion()))
         data().DefaultedDefaultConstructorIsConstexpr = false;
 

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Mon Apr 22 10:31:51 2013
@@ -289,7 +289,7 @@ static void computeDeclRefDependence(AST
   //          expression that is value-dependent [C++11]
   if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
     if ((Ctx.getLangOpts().CPlusPlus11 ?
-           Var->getType()->isLiteralType() :
+           Var->getType()->isLiteralType(Ctx) :
            Var->getType()->isIntegralOrEnumerationType()) &&
         (Var->getType().isConstQualified() ||
          Var->getType()->isReferenceType())) {

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Apr 22 10:31:51 2013
@@ -290,7 +290,7 @@ namespace {
 
     // Note that we intentionally use std::map here so that references to
     // values are stable.
-    typedef std::map<const Expr*, APValue> MapTy;
+    typedef std::map<const void*, APValue> MapTy;
     typedef MapTy::const_iterator temp_iterator;
     /// Temporaries - Temporary lvalues materialized within this stack frame.
     MapTy Temporaries;
@@ -913,6 +913,14 @@ static bool EvaluateComplex(const Expr *
 // Misc utilities
 //===----------------------------------------------------------------------===//
 
+/// Evaluate an expression to see if it had side-effects, and discard its
+/// result.
+static void EvaluateIgnoredValue(EvalInfo &Info, const Expr *E) {
+  APValue Scratch;
+  if (!Evaluate(Scratch, Info, E))
+    Info.EvalStatus.HasSideEffects = true;
+}
+
 /// Should this call expression be treated as a string literal?
 static bool IsStringLiteralCall(const CallExpr *E) {
   unsigned Builtin = E->isBuiltinCall();
@@ -1046,7 +1054,7 @@ static bool CheckLValueConstantExpressio
 /// Check that this core constant expression is of literal type, and if not,
 /// produce an appropriate diagnostic.
 static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
-  if (!E->isRValue() || E->getType()->isLiteralType())
+  if (!E->isRValue() || E->getType()->isLiteralType(Info.Ctx))
     return true;
 
   // Prvalue constant expressions must be of literal types.
@@ -1461,6 +1469,15 @@ static bool EvaluateVarDeclInit(EvalInfo
     return true;
   }
 
+  // If this is a local variable, dig out its value.
+  if (VD->hasLocalStorage() && Frame && Frame->Index > 1) {
+    Result = Frame->Temporaries[VD];
+    // If we've carried on past an unevaluatable local variable initializer,
+    // we can't go any further. This can happen during potential constant
+    // expression checking.
+    return !Result.isUninit();
+  }
+
   // Dig out the initializer, and use the declaration which it's attached to.
   const Expr *Init = VD->getAnyInitializer(VD);
   if (!Init || Init->isValueDependent()) {
@@ -1803,7 +1820,9 @@ static bool HandleLValueToRValueConversi
       return false;
     }
 
-    if (!isa<ParmVarDecl>(VD)) {
+    // Unless we're looking at a local variable or argument in a constexpr call,
+    // the variable we're reading must be const.
+    if (LVal.CallIndex <= 1 || !VD->hasLocalStorage()) {
       if (VD->isConstexpr()) {
         // OK, we can read this variable.
       } else if (VT->isIntegralOrEnumerationType()) {
@@ -1911,7 +1930,7 @@ static bool EvaluateObjectArgument(EvalI
   if (Object->isGLValue())
     return EvaluateLValue(Object, This, Info);
 
-  if (Object->getType()->isLiteralType())
+  if (Object->getType()->isLiteralType(Info.Ctx))
     return EvaluateTemporary(Object, This, Info);
 
   return false;
@@ -2060,20 +2079,61 @@ enum EvalStmtResult {
 };
 }
 
+static bool EvaluateDecl(EvalInfo &Info, const Decl *D) {
+  if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
+    // We don't need to evaluate the initializer for a static local.
+    if (!VD->hasLocalStorage())
+      return true;
+
+    LValue Result;
+    Result.set(VD, Info.CurrentCall->Index);
+    APValue &Val = Info.CurrentCall->Temporaries[VD];
+
+    if (!EvaluateInPlace(Val, Info, Result, VD->getInit())) {
+      // Wipe out any partially-computed value, to allow tracking that this
+      // evaluation failed.
+      Val = APValue();
+      return false;
+    }
+  }
+
+  return true;
+}
+
 // Evaluate a statement.
 static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
                                    const Stmt *S) {
+  // FIXME: Mark all temporaries in the current frame as destroyed at
+  // the end of each full-expression.
   switch (S->getStmtClass()) {
   default:
+    if (const Expr *E = dyn_cast<Expr>(S)) {
+      EvaluateIgnoredValue(Info, E);
+      // Don't bother evaluating beyond an expression-statement which couldn't
+      // be evaluated.
+      if (Info.EvalStatus.HasSideEffects && !Info.keepEvaluatingAfterFailure())
+        return ESR_Failed;
+      return ESR_Succeeded;
+    }
+
+    Info.Diag(S->getLocStart());
     return ESR_Failed;
 
   case Stmt::NullStmtClass:
-  case Stmt::DeclStmtClass:
     return ESR_Succeeded;
 
+  case Stmt::DeclStmtClass: {
+    const DeclStmt *DS = cast<DeclStmt>(S);
+    for (DeclStmt::const_decl_iterator DclIt = DS->decl_begin(),
+           DclEnd = DS->decl_end(); DclIt != DclEnd; ++DclIt)
+      if (!EvaluateDecl(Info, *DclIt) && !Info.keepEvaluatingAfterFailure())
+        return ESR_Failed;
+    return ESR_Succeeded;
+  }
+
   case Stmt::ReturnStmtClass: {
     const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
-    if (!Evaluate(Result, Info, RetExpr))
+    if (RetExpr && !Evaluate(Result, Info, RetExpr))
       return ESR_Failed;
     return ESR_Returned;
   }
@@ -2088,6 +2148,28 @@ static EvalStmtResult EvaluateStmt(APVal
     }
     return ESR_Succeeded;
   }
+
+  case Stmt::IfStmtClass: {
+    const IfStmt *IS = cast<IfStmt>(S);
+
+    // Evaluate the condition, as either a var decl or as an expression.
+    bool Cond;
+    if (VarDecl *CondDecl = IS->getConditionVariable()) {
+      if (!EvaluateDecl(Info, CondDecl))
+        return ESR_Failed;
+      if (!HandleConversionToBool(Info.CurrentCall->Temporaries[CondDecl],
+                                  Cond))
+        return ESR_Failed;
+    } else if (!EvaluateAsBooleanCondition(IS->getCond(), Cond, Info))
+      return ESR_Failed;
+
+    if (const Stmt *SubStmt = Cond ? IS->getThen() : IS->getElse()) {
+      EvalStmtResult ESR = EvaluateStmt(Result, Info, SubStmt);
+      if (ESR != ESR_Succeeded)
+        return ESR;
+    }
+    return ESR_Succeeded;
+  }
   }
 }
 
@@ -2181,7 +2263,10 @@ static bool HandleFunctionCall(SourceLoc
     return false;
 
   CallStackFrame Frame(Info, CallLoc, Callee, This, ArgValues.data());
-  return EvaluateStmt(Result, Info, Body) == ESR_Returned;
+  EvalStmtResult ESR = EvaluateStmt(Result, Info, Body);
+  if (ESR == ESR_Succeeded)
+    Info.Diag(Callee->getLocEnd(), diag::note_constexpr_no_return);
+  return ESR == ESR_Returned;
 }
 
 /// Evaluate a constructor call.
@@ -2207,7 +2292,9 @@ static bool HandleConstructorCall(Source
   // If it's a delegating constructor, just delegate.
   if (Definition->isDelegatingConstructor()) {
     CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
-    return EvaluateInPlace(Result, Info, This, (*I)->getInit());
+    if (!EvaluateInPlace(Result, Info, This, (*I)->getInit()))
+      return false;
+    return EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed;
   }
 
   // For a trivial copy or move constructor, perform an APValue copy. This is
@@ -2307,7 +2394,8 @@ static bool HandleConstructorCall(Source
     }
   }
 
-  return Success;
+  return Success &&
+         EvaluateStmt(Result, Info, Definition->getBody()) != ESR_Failed;
 }
 
 //===----------------------------------------------------------------------===//
@@ -2660,9 +2748,7 @@ public:
 
   /// Visit a value which is evaluated, but whose value is ignored.
   void VisitIgnoredValue(const Expr *E) {
-    APValue Scratch;
-    if (!Evaluate(Scratch, Info, E))
-      Info.EvalStatus.HasSideEffects = true;
+    EvaluateIgnoredValue(Info, E);
   }
 };
 
@@ -2868,7 +2954,7 @@ bool LValueExprEvaluator::VisitDeclRefEx
 
 bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
   if (!VD->getType()->isReferenceType()) {
-    if (isa<ParmVarDecl>(VD)) {
+    if (VD->hasLocalStorage() && Info.CurrentCall->Index > 1) {
       Result.set(VD, Info.CurrentCall->Index);
       return true;
     }

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Mon Apr 22 10:31:51 2013
@@ -1142,16 +1142,20 @@ bool QualType::isTriviallyCopyableType(A
 
 
 
-bool Type::isLiteralType() const {
+bool Type::isLiteralType(ASTContext &Ctx) const {
   if (isDependentType())
     return false;
 
-  // C++0x [basic.types]p10:
+  // C++1y [basic.types]p10:
+  //   A type is a literal type if it is:
+  //   -- cv void; or
+  if (Ctx.getLangOpts().CPlusPlus1y && isVoidType())
+    return true;
+
+  // C++11 [basic.types]p10:
   //   A type is a literal type if it is:
   //   [...]
-  //   -- an array of literal type.
-  // Extension: variable arrays cannot be literal types, since they're
-  // runtime-sized.
+  //   -- an array of literal type other than an array of runtime bound; or
   if (isVariableArrayType())
     return false;
   const Type *BaseTy = getBaseElementTypeUnsafe();
@@ -1162,7 +1166,7 @@ bool Type::isLiteralType() const {
   if (BaseTy->isIncompleteType())
     return false;
 
-  // C++0x [basic.types]p10:
+  // C++11 [basic.types]p10:
   //   A type is a literal type if it is:
   //    -- a scalar type; or
   // As an extension, Clang treats vector types and complex types as

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Mon Apr 22 10:31:51 2013
@@ -7626,7 +7626,7 @@ void Sema::AddInitializerToDecl(Decl *Re
       }
 
     // Suggest adding 'constexpr' in C++11 for literal types.
-    } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType()) {
+    } else if (getLangOpts().CPlusPlus11 && DclT->isLiteralType(Context)) {
       Diag(VDecl->getLocation(), diag::err_in_class_initializer_literal_type)
         << DclT << Init->getSourceRange()
         << FixItHint::CreateInsertion(VDecl->getLocStart(), "constexpr ");

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Apr 22 10:31:51 2013
@@ -775,12 +775,13 @@ bool Sema::CheckConstexprFunctionDecl(co
 }
 
 /// Check the given declaration statement is legal within a constexpr function
-/// body. C++0x [dcl.constexpr]p3,p4.
+/// body. C++11 [dcl.constexpr]p3,p4, and C++1y [dcl.constexpr]p3.
 ///
-/// \return true if the body is OK, false if we have diagnosed a problem.
+/// \return true if the body is OK (maybe only as an extension), false if we
+///         have diagnosed a problem.
 static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl,
-                                   DeclStmt *DS) {
-  // C++0x [dcl.constexpr]p3 and p4:
+                                   DeclStmt *DS, SourceLocation &Cxx1yLoc) {
+  // C++11 [dcl.constexpr]p3 and p4:
   //  The definition of a constexpr function(p3) or constructor(p4) [...] shall
   //  contain only
   for (DeclStmt::decl_iterator DclIt = DS->decl_begin(),
@@ -791,6 +792,7 @@ static bool CheckConstexprDeclStmt(Sema
     case Decl::UsingShadow:
     case Decl::UsingDirective:
     case Decl::UnresolvedUsingTypename:
+    case Decl::UnresolvedUsingValue:
       //   - static_assert-declarations
       //   - using-declarations,
       //   - using-directives,
@@ -814,20 +816,62 @@ static bool CheckConstexprDeclStmt(Sema
 
     case Decl::Enum:
     case Decl::CXXRecord:
-      // As an extension, we allow the declaration (but not the definition) of
-      // classes and enumerations in all declarations, not just in typedef and
-      // alias declarations.
-      if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition()) {
-        SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_type_definition)
+      // C++1y allows types to be defined, not just declared.
+      if (cast<TagDecl>(*DclIt)->isThisDeclarationADefinition())
+        SemaRef.Diag(DS->getLocStart(),
+                     SemaRef.getLangOpts().CPlusPlus1y
+                       ? diag::warn_cxx11_compat_constexpr_type_definition
+                       : diag::ext_constexpr_type_definition)
           << isa<CXXConstructorDecl>(Dcl);
-        return false;
-      }
       continue;
 
-    case Decl::Var:
-      SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_var_declaration)
+    case Decl::EnumConstant:
+    case Decl::IndirectField:
+    case Decl::ParmVar:
+      // These can only appear with other declarations which are banned in
+      // C++11 and permitted in C++1y, so ignore them.
+      continue;
+
+    case Decl::Var: {
+      // C++1y [dcl.constexpr]p3 allows anything except:
+      //   a definition of a variable of non-literal type or of static or
+      //   thread storage duration or for which no initialization is performed.
+      VarDecl *VD = cast<VarDecl>(*DclIt);
+      if (VD->isThisDeclarationADefinition()) {
+        if (VD->isStaticLocal()) {
+          SemaRef.Diag(VD->getLocation(),
+                       diag::err_constexpr_local_var_static)
+            << isa<CXXConstructorDecl>(Dcl)
+            << (VD->getTLSKind() == VarDecl::TLS_Dynamic);
+          return false;
+        }
+        if (SemaRef.RequireLiteralType(
+              VD->getLocation(), VD->getType(),
+              diag::err_constexpr_local_var_non_literal_type,
+              isa<CXXConstructorDecl>(Dcl)))
+          return false;
+        if (!VD->hasInit()) {
+          SemaRef.Diag(VD->getLocation(),
+                       diag::err_constexpr_local_var_no_init)
+            << isa<CXXConstructorDecl>(Dcl);
+          return false;
+        }
+      }
+      SemaRef.Diag(VD->getLocation(),
+                   SemaRef.getLangOpts().CPlusPlus1y
+                    ? diag::warn_cxx11_compat_constexpr_local_var
+                    : diag::ext_constexpr_local_var)
         << isa<CXXConstructorDecl>(Dcl);
-      return false;
+      continue;
+    }
+
+    case Decl::NamespaceAlias:
+    case Decl::Function:
+      // These are disallowed in C++11 and permitted in C++1y. Allow them
+      // everywhere as an extension.
+      if (!Cxx1yLoc.isValid())
+        Cxx1yLoc = DS->getLocStart();
+      continue;
 
     default:
       SemaRef.Diag(DS->getLocStart(), diag::err_constexpr_body_invalid_stmt)
@@ -876,6 +920,124 @@ static void CheckConstexprCtorInitialize
   }
 }
 
+/// Check the provided statement is allowed in a constexpr function
+/// definition.
+static bool
+CheckConstexprFunctionStmt(Sema &SemaRef, const FunctionDecl *Dcl, Stmt *S,
+                           llvm::SmallVectorImpl<SourceLocation> &ReturnStmts,
+                           SourceLocation &Cxx1yLoc) {
+  // - its function-body shall be [...] a compound-statement that contains only
+  switch (S->getStmtClass()) {
+  case Stmt::NullStmtClass:
+    //   - null statements,
+    return true;
+
+  case Stmt::DeclStmtClass:
+    //   - static_assert-declarations
+    //   - using-declarations,
+    //   - using-directives,
+    //   - typedef declarations and alias-declarations that do not define
+    //     classes or enumerations,
+    if (!CheckConstexprDeclStmt(SemaRef, Dcl, cast<DeclStmt>(S), Cxx1yLoc))
+      return false;
+    return true;
+
+  case Stmt::ReturnStmtClass:
+    //   - and exactly one return statement;
+    if (isa<CXXConstructorDecl>(Dcl)) {
+      // C++1y allows return statements in constexpr constructors.
+      if (!Cxx1yLoc.isValid())
+        Cxx1yLoc = S->getLocStart();
+      return true;
+    }
+
+    ReturnStmts.push_back(S->getLocStart());
+    return true;
+
+  case Stmt::CompoundStmtClass: {
+    // C++1y allows compound-statements.
+    if (!Cxx1yLoc.isValid())
+      Cxx1yLoc = S->getLocStart();
+
+    CompoundStmt *CompStmt = cast<CompoundStmt>(S);
+    for (CompoundStmt::body_iterator BodyIt = CompStmt->body_begin(),
+           BodyEnd = CompStmt->body_end(); BodyIt != BodyEnd; ++BodyIt) {
+      if (!CheckConstexprFunctionStmt(SemaRef, Dcl, *BodyIt, ReturnStmts,
+                                      Cxx1yLoc))
+        return false;
+    }
+    return true;
+  }
+
+  case Stmt::AttributedStmtClass:
+    if (!Cxx1yLoc.isValid())
+      Cxx1yLoc = S->getLocStart();
+    return true;
+
+  case Stmt::IfStmtClass: {
+    // C++1y allows if-statements.
+    if (!Cxx1yLoc.isValid())
+      Cxx1yLoc = S->getLocStart();
+
+    IfStmt *If = cast<IfStmt>(S);
+    if (!CheckConstexprFunctionStmt(SemaRef, Dcl, If->getThen(), ReturnStmts,
+                                    Cxx1yLoc))
+      return false;
+    if (If->getElse() &&
+        !CheckConstexprFunctionStmt(SemaRef, Dcl, If->getElse(), ReturnStmts,
+                                    Cxx1yLoc))
+      return false;
+    return true;
+  }
+
+  case Stmt::WhileStmtClass:
+  case Stmt::DoStmtClass:
+  case Stmt::ForStmtClass:
+  case Stmt::CXXForRangeStmtClass:
+  case Stmt::ContinueStmtClass:
+    // C++1y allows all of these. We don't allow them as extensions in C++11,
+    // because they don't make sense without variable mutation.
+    if (!SemaRef.getLangOpts().CPlusPlus1y)
+      break;
+    if (!Cxx1yLoc.isValid())
+      Cxx1yLoc = S->getLocStart();
+    for (Stmt::child_range Children = S->children(); Children; ++Children)
+      if (*Children &&
+          !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts,
+                                      Cxx1yLoc))
+        return false;
+    return true;
+
+  case Stmt::SwitchStmtClass:
+  case Stmt::CaseStmtClass:
+  case Stmt::DefaultStmtClass:
+  case Stmt::BreakStmtClass:
+    // C++1y allows switch-statements, and since they don't need variable
+    // mutation, we can reasonably allow them in C++11 as an extension.
+    if (!Cxx1yLoc.isValid())
+      Cxx1yLoc = S->getLocStart();
+    for (Stmt::child_range Children = S->children(); Children; ++Children)
+      if (*Children &&
+          !CheckConstexprFunctionStmt(SemaRef, Dcl, *Children, ReturnStmts,
+                                      Cxx1yLoc))
+        return false;
+    return true;
+
+  default:
+    if (!isa<Expr>(S))
+      break;
+
+    // C++1y allows expression-statements.
+    if (!Cxx1yLoc.isValid())
+      Cxx1yLoc = S->getLocStart();
+    return true;
+  }
+
+  SemaRef.Diag(S->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+    << isa<CXXConstructorDecl>(Dcl);
+  return false;
+}
+
 /// Check the body for the given constexpr function declaration only contains
 /// the permitted types of statement. C++11 [dcl.constexpr]p3,p4.
 ///
@@ -896,43 +1058,24 @@ bool Sema::CheckConstexprFunctionBody(co
     return false;
   }
 
+  SmallVector<SourceLocation, 4> ReturnStmts;
+
   // - its function-body shall be [...] a compound-statement that contains only
+  //   [... list of cases ...]
   CompoundStmt *CompBody = cast<CompoundStmt>(Body);
-
-  SmallVector<SourceLocation, 4> ReturnStmts;
+  SourceLocation Cxx1yLoc;
   for (CompoundStmt::body_iterator BodyIt = CompBody->body_begin(),
          BodyEnd = CompBody->body_end(); BodyIt != BodyEnd; ++BodyIt) {
-    switch ((*BodyIt)->getStmtClass()) {
-    case Stmt::NullStmtClass:
-      //   - null statements,
-      continue;
-
-    case Stmt::DeclStmtClass:
-      //   - static_assert-declarations
-      //   - using-declarations,
-      //   - using-directives,
-      //   - typedef declarations and alias-declarations that do not define
-      //     classes or enumerations,
-      if (!CheckConstexprDeclStmt(*this, Dcl, cast<DeclStmt>(*BodyIt)))
-        return false;
-      continue;
-
-    case Stmt::ReturnStmtClass:
-      //   - and exactly one return statement;
-      if (isa<CXXConstructorDecl>(Dcl))
-        break;
-
-      ReturnStmts.push_back((*BodyIt)->getLocStart());
-      continue;
-
-    default:
-      break;
-    }
+    if (!CheckConstexprFunctionStmt(*this, Dcl, *BodyIt, ReturnStmts, Cxx1yLoc))
+      return false;
+  }
 
-    Diag((*BodyIt)->getLocStart(), diag::err_constexpr_body_invalid_stmt)
+  if (Cxx1yLoc.isValid())
+    Diag(Cxx1yLoc,
+         getLangOpts().CPlusPlus1y
+           ? diag::warn_cxx11_compat_constexpr_body_invalid_stmt
+           : diag::ext_constexpr_body_invalid_stmt)
       << isa<CXXConstructorDecl>(Dcl);
-    return false;
-  }
 
   if (const CXXConstructorDecl *Constructor
         = dyn_cast<CXXConstructorDecl>(Dcl)) {
@@ -988,14 +1131,23 @@ bool Sema::CheckConstexprFunctionBody(co
     }
   } else {
     if (ReturnStmts.empty()) {
-      Diag(Dcl->getLocation(), diag::err_constexpr_body_no_return);
+      // C++1y doesn't require constexpr functions to contain a 'return'
+      // statement. We still do, unless the return type is void, because
+      // otherwise if there's no return statement, the function cannot
+      // be used in a core constant expression.
+      Diag(Dcl->getLocation(),
+           getLangOpts().CPlusPlus1y && Dcl->getResultType()->isVoidType()
+             ? diag::warn_cxx11_compat_constexpr_body_no_return
+             : diag::err_constexpr_body_no_return);
       return false;
     }
     if (ReturnStmts.size() > 1) {
-      Diag(ReturnStmts.back(), diag::err_constexpr_body_multiple_return);
+      Diag(ReturnStmts.back(),
+           getLangOpts().CPlusPlus1y
+             ? diag::warn_cxx11_compat_constexpr_body_multiple_return
+             : diag::ext_constexpr_body_multiple_return);
       for (unsigned I = 0; I < ReturnStmts.size() - 1; ++I)
         Diag(ReturnStmts[I], diag::note_constexpr_body_previous_return);
-      return false;
     }
   }
 

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Apr 22 10:31:51 2013
@@ -3137,7 +3137,7 @@ static bool EvaluateUnaryTypeTrait(Sema
   case UTT_IsPOD:
     return T.isPODType(Self.Context);
   case UTT_IsLiteral:
-    return T->isLiteralType();
+    return T->isLiteralType(Self.Context);
   case UTT_IsEmpty:
     if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl())
       return !RD->isUnion() && RD->isEmpty();

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Mon Apr 22 10:31:51 2013
@@ -4809,7 +4809,7 @@ bool Sema::RequireLiteralType(SourceLoca
   QualType ElemType = Context.getBaseElementType(T);
   RequireCompleteType(Loc, ElemType, 0);
 
-  if (T->isLiteralType())
+  if (T->isLiteralType(Context))
     return false;
 
   if (Diagnoser.Suppressed)
@@ -4851,7 +4851,7 @@ bool Sema::RequireLiteralType(SourceLoca
   } else if (RD->hasNonLiteralTypeFieldsOrBases()) {
     for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
          E = RD->bases_end(); I != E; ++I) {
-      if (!I->getType()->isLiteralType()) {
+      if (!I->getType()->isLiteralType(Context)) {
         Diag(I->getLocStart(),
              diag::note_non_literal_base_class)
           << RD << I->getType() << I->getSourceRange();
@@ -4860,7 +4860,7 @@ bool Sema::RequireLiteralType(SourceLoca
     }
     for (CXXRecordDecl::field_iterator I = RD->field_begin(),
          E = RD->field_end(); I != E; ++I) {
-      if (!I->getType()->isLiteralType() ||
+      if (!I->getType()->isLiteralType(Context) ||
           I->getType().isVolatileQualified()) {
         Diag(I->getLocation(), diag::note_non_literal_field)
           << RD << *I << I->getType()

Modified: cfe/trunk/test/CXX/basic/basic.types/p10.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.types/p10.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.types/p10.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.types/p10.cpp Mon Apr 22 10:31:51 2013
@@ -1,9 +1,16 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1y %s -DCXX1Y
 
 struct NonLiteral { NonLiteral(); };
 
 // A type is a literal type if it is:
 
+// [C++1y] - void
+constexpr void f() {}
+#ifndef CXX1Y
+// expected-error at -2 {{'void' is not a literal type}}
+#endif
+
 // - a scalar type
 constexpr int f1(double) { return 0; }
 
@@ -11,7 +18,6 @@ constexpr int f1(double) { return 0; }
 struct S { S(); };
 constexpr int f2(S &) { return 0; }
 
-// FIXME: I'm not entirely sure whether the following is legal or not...
 struct BeingDefined;
 extern BeingDefined beingdefined;
 struct BeingDefined { 
@@ -117,7 +123,7 @@ struct MemberType {
 constexpr int f(MemberType<int>) { return 0; }
 constexpr int f(MemberType<NonLiteral>) { return 0; } // expected-error {{not a literal type}}
 
-// - an array of literal type
+// - an array of literal type [C++1y] other than an array of runtime bound
 struct ArrGood {
   Agg agg[24];
   double d[12];
@@ -130,3 +136,7 @@ struct ArrBad {
   S s[3]; // expected-note {{data member 's' of non-literal type 'S [3]'}}
 };
 constexpr int f(ArrBad) { return 0; } // expected-error {{1st parameter type 'ArrBad' is not a literal type}}
+
+constexpr int arb(int n) {
+  int a[n]; // expected-error {{variable of non-literal type 'int [n]' cannot be defined in a constexpr function}}
+}

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p3.cpp Mon Apr 22 10:31:51 2013
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -verify -std=c++11 %s
+// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++11 -Werror=c++1y-extensions %s
+// RUN: %clang_cc1 -verify -fcxx-exceptions -triple=x86_64-linux-gnu -std=c++1y -DCXX1Y %s
 
 namespace N {
   typedef char C;
@@ -8,7 +9,7 @@ namespace M {
   typedef double D;
 }
 
-struct NonLiteral { // expected-note 2{{no constexpr constructors}}
+struct NonLiteral { // expected-note 3{{no constexpr constructors}}
   NonLiteral() {}
   NonLiteral(int) {}
 };
@@ -37,7 +38,10 @@ struct T : SS, NonLiteral { // expected-
 
   //  - its return type shall be a literal type;
   constexpr NonLiteral NonLiteralReturn() const { return {}; } // expected-error {{constexpr function's return type 'NonLiteral' is not a literal type}}
-  constexpr void VoidReturn() const { return; } // expected-error {{constexpr function's return type 'void' is not a literal type}}
+  constexpr void VoidReturn() const { return; }
+#ifndef CXX1Y
+  // expected-error at -2 {{constexpr function's return type 'void' is not a literal type}}
+#endif
   constexpr ~T(); // expected-error {{destructor cannot be marked constexpr}}
   typedef NonLiteral F() const;
   constexpr F NonLiteralReturn2; // ok until definition
@@ -49,12 +53,17 @@ struct T : SS, NonLiteral { // expected-
 
   //  - its function-body shall be = delete, = default,
   constexpr int Deleted() const = delete;
-  // It's not possible for the function-body to legally be "= default" here.
+  // It's not possible for the function-body to legally be "= default" here
+  // (that is, for a non-constructor function) in C++11.
   // Other than constructors, only the copy- and move-assignment operators and
   // destructor can be defaulted. Destructors can't be constexpr since they
   // don't have a literal return type. Defaulted assignment operators can't be
   // constexpr since they can't be const.
-  constexpr T &operator=(const T&) = default; // expected-error {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}} expected-warning {{C++1y}}
+  constexpr T &operator=(const T&) = default;
+#ifndef CXX1Y
+  // expected-error at -2 {{an explicitly-defaulted copy assignment operator may not have 'const', 'constexpr' or 'volatile' qualifiers}}
+  // expected-warning at -3 {{C++1y}}
+#endif
 };
 struct U {
   constexpr U SelfReturn() const;
@@ -65,8 +74,8 @@ struct V : virtual U { // expected-note
   constexpr int F() const { return 0; } // expected-error {{constexpr member function not allowed in struct with virtual base class}}
 };
 
-//  or a compound-statememt that contains only
-constexpr int AllowedStmts() {
+//  or a compound-statememt that contains only [CXX11]
+constexpr int AllowedStmtsCXX11() {
   //  - null statements
   ;
 
@@ -91,34 +100,122 @@ constexpr int AllowedStmts() {
   //  - and exactly one return statement
   return sizeof(K) + sizeof(C) + sizeof(K);
 }
+
+//  or a compound-statement that does not contain [CXX1Y]
+constexpr int DisallowedStmtsCXX1Y_1() {
+  //  - an asm-definition
+  asm("int3"); // expected-error {{statement not allowed in constexpr function}}
+  return 0;
+}
+constexpr int DisallowedStmtsCXX1Y_2() {
+  //  - a goto statement
+  goto x; // expected-error {{statement not allowed in constexpr function}}
+x:
+  return 0;
+}
+constexpr int DisallowedStmtsCXX1Y_3() {
+  //  - a try-block,
+  try {} catch (...) {} // expected-error {{statement not allowed in constexpr function}}
+  return 0;
+}
+constexpr int DisallowedStmtsCXX1Y_4() {
+  //  - a definition of a variable of non-literal type
+  NonLiteral nl; // expected-error {{variable of non-literal type 'NonLiteral' cannot be defined in a constexpr function}}
+  return 0;
+}
+constexpr int DisallowedStmtsCXX1Y_5() {
+  //  - a definition of a variable of static storage duration
+  static constexpr int n = 123; // expected-error {{static variable not permitted in a constexpr function}}
+  return n;
+}
+constexpr int DisallowedStmtsCXX1Y_6() {
+  //  - a definition of a variable of thread storage duration
+  thread_local constexpr int n = 123; // expected-error {{thread_local variable not permitted in a constexpr function}}
+  return n;
+}
+constexpr int DisallowedStmtsCXX1Y_7() {
+  //  - a definition of a variable for which no initialization is performed
+  int n; // expected-error {{variables defined in a constexpr function must be initialized}}
+  return 0;
+}
+
 constexpr int ForStmt() {
-  for (int n = 0; n < 10; ++n) // expected-error {{statement not allowed in constexpr function}}
+  for (int n = 0; n < 10; ++n)
+#ifndef CXX1Y
+  // expected-error at -2 {{statement not allowed in constexpr function}}
+#else
+  // FIXME: Once we support evaluating a for-statement, this diagnostic should disappear.
+  // expected-error at -6 {{never produces a constant expression}}
+  // expected-note at -6 {{subexpression}}
+#endif
     return 0;
 }
 constexpr int VarDecl() {
-  constexpr int a = 0; // expected-error {{variables cannot be declared in a constexpr function}}
+  int a = 0;
+#ifndef CXX1Y
+  // expected-error at -2 {{variable declaration in a constexpr function is a C++1y extension}}
+#endif
+  return 0;
+}
+constexpr int ConstexprVarDecl() {
+  constexpr int a = 0;
+#ifndef CXX1Y
+  // expected-error at -2 {{variable declaration in a constexpr function is a C++1y extension}}
+#endif
   return 0;
 }
+constexpr int VarWithCtorDecl() {
+  Literal a;
+#ifndef CXX1Y
+  // expected-error at -2 {{variable declaration in a constexpr function is a C++1y extension}}
+#endif
+  return 0;
+}
+NonLiteral nl;
+constexpr NonLiteral &ExternNonLiteralVarDecl() {
+  extern NonLiteral nl;
+#ifndef CXX1Y
+  // expected-error at -2 {{variable declaration in a constexpr function is a C++1y extension}}
+#endif
+  return nl;
+}
+static_assert(&ExternNonLiteralVarDecl() == &nl, "");
 constexpr int FuncDecl() {
-  constexpr int ForwardDecl(int); // expected-error {{statement not allowed in constexpr function}}
+  constexpr int ForwardDecl(int);
+#ifndef CXX1Y
+  // expected-error at -2 {{use of this statement in a constexpr function is a C++1y extension}}
+#endif
   return ForwardDecl(42);
 }
 constexpr int ClassDecl1() {
-  typedef struct { } S1; // expected-error {{types cannot be defined in a constexpr function}}
+  typedef struct { } S1;
+#ifndef CXX1Y
+  // expected-error at -2 {{type definition in a constexpr function is a C++1y extension}}
+#endif
   return 0;
 }
 constexpr int ClassDecl2() {
-  using S2 = struct { }; // expected-error {{types cannot be defined in a constexpr function}}
+  using S2 = struct { };
+#ifndef CXX1Y
+  // expected-error at -2 {{type definition in a constexpr function is a C++1y extension}}
+#endif
   return 0;
 }
 constexpr int ClassDecl3() {
-  struct S3 { }; // expected-error {{types cannot be defined in a constexpr function}}
+  struct S3 { };
+#ifndef CXX1Y
+  // expected-error at -2 {{type definition in a constexpr function is a C++1y extension}}
+#endif
   return 0;
 }
 constexpr int NoReturn() {} // expected-error {{no return statement in constexpr function}}
 constexpr int MultiReturn() {
-  return 0; // expected-note {{return statement}}
-  return 0; // expected-error {{multiple return statements in constexpr function}}
+  return 0;
+  return 0;
+#ifndef CXX1Y
+  // expected-error at -2 {{multiple return statements in constexpr function}}
+  // expected-note at -4 {{return statement}}
+#endif
 }
 
 //  - every constructor call and implicit conversion used in initializing the
@@ -153,3 +250,46 @@ namespace rdar13584715 {
     }
   }
 }
+
+namespace std_example {
+  constexpr int square(int x) {
+    return x * x;
+  }
+  constexpr long long_max() {
+    return 2147483647;
+  }
+  constexpr int abs(int x) {
+    if (x < 0)
+#ifndef CXX1Y
+      // expected-error at -2 {{C++1y}}
+#endif
+      x = -x;
+    return x;
+  }
+  constexpr int first(int n) {
+    static int value = n; // expected-error {{static variable not permitted}}
+    return value;
+  }
+  constexpr int uninit() {
+    int a; // expected-error {{must be initialized}}
+    return a;
+  }
+  // FIXME: Once we support variable mutation, this can produce a
+  // constant expression.
+  constexpr int prev(int x) { // expected-error {{never produces a constant expression}}
+    return --x; // expected-note {{subexpression}}
+  }
+  constexpr int g(int x, int n) {
+    int r = 1;
+    while (--n > 0) r *= x;
+    return r;
+  }
+#ifndef CXX1Y
+    // expected-error at -5 {{C++1y}}
+    // expected-error at -5 {{statement not allowed}}
+#else
+    // FIXME: This should be allowed.
+    // expected-error at -10 {{never produces a constant}}
+    // expected-note at -9 {{subexpression}}
+#endif
+}

Modified: cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp (original)
+++ cfe/trunk/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p4.cpp Mon Apr 22 10:31:51 2013
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions %s
+// RUN: %clang_cc1 -verify -std=c++11 -fcxx-exceptions -Werror=c++1y-extensions %s
+// RUN: %clang_cc1 -verify -std=c++1y -fcxx-exceptions -DCXX1Y %s
 
 namespace N {
   typedef char C;
@@ -82,26 +83,51 @@ struct V {
   }
 
   constexpr V(int(&)[1]) {
-    for (int n = 0; n < 10; ++n) // expected-error {{statement not allowed in constexpr constructor}}
+    for (int n = 0; n < 10; ++n)
       /**/;
+#ifndef CXX1Y
+    // expected-error at -3 {{statement not allowed in constexpr constructor}}
+#else
+    // FIXME: Once we support evaluating a for-statement, this diagnostic should disappear.
+    // expected-error at -7 {{never produces a constant expression}}
+    // expected-note at -7 {{subexpression}}
+#endif
   }
   constexpr V(int(&)[2]) {
-    constexpr int a = 0; // expected-error {{variables cannot be declared in a constexpr constructor}}
+    constexpr int a = 0;
+#ifndef CXX1Y
+    // expected-error at -2 {{variable declaration in a constexpr constructor is a C++1y extension}}
+#endif
   }
   constexpr V(int(&)[3]) {
-    constexpr int ForwardDecl(int); // expected-error {{statement not allowed in constexpr constructor}}
+    constexpr int ForwardDecl(int);
+#ifndef CXX1Y
+    // expected-error at -2 {{use of this statement in a constexpr constructor is a C++1y extension}}
+#endif
   }
   constexpr V(int(&)[4]) {
-    typedef struct { } S1; // expected-error {{types cannot be defined in a constexpr constructor}}
+    typedef struct { } S1;
+#ifndef CXX1Y
+    // expected-error at -2 {{type definition in a constexpr constructor is a C++1y extension}}
+#endif
   }
   constexpr V(int(&)[5]) {
-    using S2 = struct { }; // expected-error {{types cannot be defined in a constexpr constructor}}
+    using S2 = struct { };
+#ifndef CXX1Y
+    // expected-error at -2 {{type definition in a constexpr constructor is a C++1y extension}}
+#endif
   }
   constexpr V(int(&)[6]) {
-    struct S3 { }; // expected-error {{types cannot be defined in a constexpr constructor}}
+    struct S3 { };
+#ifndef CXX1Y
+    // expected-error at -2 {{type definition in a constexpr constructor is a C++1y extension}}
+#endif
   }
   constexpr V(int(&)[7]) {
-    return; // expected-error {{statement not allowed in constexpr constructor}}
+    return;
+#ifndef CXX1Y
+    // expected-error at -2 {{use of this statement in a constexpr constructor is a C++1y extension}}
+#endif
   }
 };
 

Modified: cfe/trunk/test/CXX/except/except.spec/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/except/except.spec/p1.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/test/CXX/except/except.spec/p1.cpp (original)
+++ cfe/trunk/test/CXX/except/except.spec/p1.cpp Mon Apr 22 10:31:51 2013
@@ -55,7 +55,7 @@ namespace noex {
   struct A {};
 
   void g1() noexcept(A()); // expected-error {{not contextually convertible}}
-  void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}}
+  void g2(bool b) noexcept(b); // expected-error {{argument to noexcept specifier must be a constant expression}} expected-note {{read of non-const variable 'b'}} expected-note {{here}}
 
 }
 

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=180022&r1=180021&r2=180022&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Mon Apr 22 10:31:51 2013
@@ -1312,6 +1312,13 @@ namespace InvalidClasses {
   }
 }
 
+namespace NamespaceAlias {
+  constexpr int f() {
+    namespace NS = NamespaceAlias; // expected-warning {{use of this statement in a constexpr function is a C++1y extension}}
+    return &NS::f != nullptr;
+  }
+}
+
 // Constructors can be implicitly constexpr, even for a non-literal type.
 namespace ImplicitConstexpr {
   struct Q { Q() = default; Q(const Q&) = default; Q(Q&&) = default; ~Q(); }; // expected-note 3{{here}}

Added: cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp?rev=180022&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp (added)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx1y.cpp Mon Apr 22 10:31:51 2013
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -std=c++1y -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu
+
+struct S {
+  // dummy ctor to make this a literal type
+  constexpr S(int);
+
+  S();
+
+  int arr[10];
+
+  constexpr int &get(int n) { return arr[n]; }
+  constexpr const int &get(int n) const { return arr[n]; }
+};
+
+S s = S();
+const S &sr = s;
+static_assert(&s.get(4) - &sr.get(2) == 2, "");
+
+// Compound-statements can be used in constexpr functions.
+constexpr int e() {{{{}} return 5; }}
+static_assert(e() == 5, "");
+
+// Types can be defined in constexpr functions.
+constexpr int f() {
+  enum E { e1, e2, e3 };
+
+  struct S {
+    constexpr S(E e) : e(e) {}
+    constexpr int get() { return e; }
+    E e;
+  };
+
+  return S(e2).get();
+}
+static_assert(f() == 1, "");
+
+// Variables can be declared in constexpr functions.
+constexpr int g(int k) {
+  const int n = 9;
+  int k2 = k * k;
+  int k3 = k2 * k;
+  return 3 * k3 + 5 * k2 + n * k - 20;
+}
+static_assert(g(2) == 42, "");
+constexpr int h(int n) {
+  static const int m = n; // expected-error {{static variable not permitted in a constexpr function}}
+  return m;
+}
+constexpr int i(int n) {
+  thread_local const int m = n; // expected-error {{thread_local variable not permitted in a constexpr function}}
+  return m;
+}
+
+// if-statements can be used in constexpr functions.
+constexpr int j(int k) {
+  if (k == 5)
+    return 1;
+  if (k == 1)
+    return 5;
+  else {
+    if (int n = 2 * k - 4) {
+      return n + 1;
+      return 2;
+    }
+  }
+} // expected-note 2{{control reached end of constexpr function}}
+static_assert(j(0) == -3, "");
+static_assert(j(1) == 5, "");
+static_assert(j(2), ""); // expected-error {{constant expression}} expected-note {{in call to 'j(2)'}}
+static_assert(j(3) == 3, "");
+static_assert(j(4) == 5, "");
+static_assert(j(5) == 1, "");
+
+// There can be 0 return-statements.
+constexpr void k() {
+}
+
+// If the return type is not 'void', no return statements => never a constant
+// expression, so still diagnose that case.
+[[noreturn]] constexpr int fn() { // expected-error {{no return statement in constexpr function}}
+  fn();
+}
+
+// We evaluate the body of a constexpr constructor, to check for side-effects.
+struct U {
+  constexpr U(int n) {
+    if (j(n)) {} // expected-note {{in call to 'j(2)'}}
+  }
+};
+constexpr U u1{1};
+constexpr U u2{2}; // expected-error {{constant expression}} expected-note {{in call to 'U(2)'}}
+
+// We allow expression-statements.
+constexpr int l(bool b) {
+  if (b)
+    throw "invalid value for b!"; // expected-note {{subexpression not valid}}
+  return 5;
+}
+static_assert(l(false) == 5, "");
+static_assert(l(true), ""); // expected-error {{constant expression}} expected-note {{in call to 'l(true)'}}
+
+// Potential constant expression checking is still applied where possible.
+constexpr int htonl(int x) { // expected-error {{never produces a constant expression}}
+  typedef unsigned char uchar;
+  uchar arr[4] = { uchar(x >> 24), uchar(x >> 16), uchar(x >> 8), uchar(x) };
+  return *reinterpret_cast<int*>(arr); // expected-note {{reinterpret_cast is not allowed in a constant expression}}
+}
+
+constexpr int maybe_htonl(bool isBigEndian, int x) {
+  if (isBigEndian)
+    return x;
+
+  typedef unsigned char uchar;
+  uchar arr[4] = { uchar(x >> 24), uchar(x >> 16), uchar(x >> 8), uchar(x) };
+  return *reinterpret_cast<int*>(arr); // expected-note {{reinterpret_cast is not allowed in a constant expression}}
+}
+
+constexpr int swapped = maybe_htonl(false, 123); // expected-error {{constant expression}} expected-note {{in call}}
+
+namespace NS {
+  constexpr int n = 0;
+}
+constexpr int namespace_alias() {
+  namespace N = NS;
+  return N::n;
+}





More information about the cfe-commits mailing list