constexpr: semantic checking for constexpr functions and constructors. Based in
part on patches by Peter Collingbourne.

We diverge from the C++11 standard in a few areas, mostly related to checking
constexpr function declarations, and not just definitions. See WG21 paper
N3308=11-0078 for details.

Function invocation substitution is not available in this patch; constexpr
functions cannot yet be used from within constant expressions.

llvm-svn: 140926
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 942c1bc..f4b6ce9 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -4770,15 +4770,11 @@
       // are implicitly inline.
       NewFD->setImplicitlyInline();
 
-      // FIXME: If this is a redeclaration, check the original declaration was
-      // marked constepr.
-
       // C++0x [dcl.constexpr]p3: functions declared constexpr are required to
       // be either constructors or to return a literal type. Therefore,
       // destructors cannot be declared constexpr.
       if (isa<CXXDestructorDecl>(NewFD))
-        Diag(D.getDeclSpec().getConstexprSpecLoc(),
-             diag::err_constexpr_dtor);
+        Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor);
     }
 
     // If __module_private__ was specified, mark the function accordingly.
@@ -5050,6 +5046,10 @@
             Previous.getResultKind() != LookupResult::FoundOverloaded) &&
            "previous declaration set still overloaded");
 
+    if (NewFD->isConstexpr() && !NewFD->isInvalidDecl() &&
+        !CheckConstexprFunctionDecl(NewFD, CCK_Declaration))
+      NewFD->setInvalidDecl();
+
     NamedDecl *PrincipalDecl = (FunctionTemplate
                                 ? cast<NamedDecl>(FunctionTemplate)
                                 : NewFD);
@@ -6963,6 +6963,10 @@
       ActivePolicy = &WP;
     }
 
+    if (FD && FD->isConstexpr() && !FD->isInvalidDecl() &&
+        !CheckConstexprFunctionBody(FD, Body))
+      FD->setInvalidDecl();
+
     assert(ExprTemporaries.empty() && "Leftover temporaries in function");
     assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
   }