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.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140926 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e29b75a..694d944 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1067,15 +1067,12 @@
                                          TemplateArgs);
   }
 
-  bool isConstexpr = D->isConstexpr();
-  // FIXME: check whether the instantiation produces a constexpr function.
-
   FunctionDecl *Function =
       FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(),
                            D->getLocation(), D->getDeclName(), T, TInfo,
                            D->getStorageClass(), D->getStorageClassAsWritten(),
                            D->isInlineSpecified(), D->hasWrittenPrototype(),
-                           isConstexpr);
+                           /*isConstexpr*/ false);
 
   if (QualifierLoc)
     Function->setQualifierInfo(QualifierLoc);
@@ -1388,9 +1385,6 @@
     if (!DC) return 0;
   }
 
-  bool isConstexpr = D->isConstexpr();
-  // FIXME: check whether the instantiation produces a constexpr function.
-
   // Build the instantiated method declaration.
   CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
   CXXMethodDecl *Method = 0;
@@ -1403,7 +1397,7 @@
                                         StartLoc, NameInfo, T, TInfo,
                                         Constructor->isExplicit(),
                                         Constructor->isInlineSpecified(),
-                                        false, isConstexpr);
+                                        false, /*isConstexpr*/ false);
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
                                        StartLoc, NameInfo, T, TInfo,
@@ -1414,14 +1408,15 @@
                                        StartLoc, NameInfo, T, TInfo,
                                        Conversion->isInlineSpecified(),
                                        Conversion->isExplicit(),
-                                       isConstexpr, Conversion->getLocEnd());
+                                       /*isConstexpr*/ false,
+                                       Conversion->getLocEnd());
   } else {
     Method = CXXMethodDecl::Create(SemaRef.Context, Record,
                                    StartLoc, NameInfo, T, TInfo,
                                    D->isStatic(),
                                    D->getStorageClassAsWritten(),
                                    D->isInlineSpecified(),
-                                   isConstexpr, D->getLocEnd());
+                                   /*isConstexpr*/ false, D->getLocEnd());
   }
 
   if (QualifierLoc)
@@ -2312,6 +2307,13 @@
                                                  EPI));
   }
 
+  // C++0x [dcl.constexpr]p6: If the instantiated template specialization of
+  // a constexpr function template satisfies the requirements for a constexpr
+  // function, then it is a constexpr function.
+  if (Tmpl->isConstexpr() &&
+      SemaRef.CheckConstexprFunctionDecl(New, Sema::CCK_Instantiation))
+    New->setConstexpr(true);
+
   const FunctionDecl* Definition = Tmpl;
 
   // Get the definition. Leaves the variable unchanged if undefined.