Default arguments are potentially constant evaluated.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 24 May 2019 21:08:12 +0000 (21:08 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Fri, 24 May 2019 21:08:12 +0000 (21:08 +0000)
We need to eagerly instantiate constexpr functions used in them even if
the default argument is never actually used, because we might evaluate
portions of it when performing semantic checks.

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

lib/Sema/SemaExpr.cpp
test/SemaCXX/default1.cpp

index 8ebc9bcf025eb0e3b0485a6bba814901011bd774..0c04f03f06d6d8612ce51e0f6f95beedbdecc164 100644 (file)
@@ -14739,6 +14739,7 @@ static bool isPotentiallyConstantEvaluatedContext(Sema &SemaRef) {
     case Sema::ExpressionEvaluationContext::ConstantEvaluated:
       // -- a manifestly constant-evaluated expression,
     case Sema::ExpressionEvaluationContext::PotentiallyEvaluated:
+    case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
     case Sema::ExpressionEvaluationContext::DiscardedStatement:
       // -- a potentially-evaluated expression,
     case Sema::ExpressionEvaluationContext::UnevaluatedList:
@@ -14754,11 +14755,6 @@ static bool isPotentiallyConstantEvaluatedContext(Sema &SemaRef) {
     case Sema::ExpressionEvaluationContext::UnevaluatedAbstract:
       // Expressions in this context are never evaluated.
       return false;
-
-    case Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed:
-      // FIXME: This is wrong. Default arguemnts are potentially constant
-      // evaluated even if they are never used.
-      return false;
   }
   llvm_unreachable("Invalid context");
 }
index fcaa2c839d6cbc776eb247fe270a709f45e3febe..3bc6f832b686bb9208ddf5683996bab7b7524c85 100644 (file)
@@ -78,3 +78,21 @@ void PR20769(int = 2);
 
 void PR20769_b(int = 1);
 void PR20769_b() { void PR20769_b(int = 2); }
+
+#if __cplusplus >= 201103L
+template<typename T> constexpr int f1() { return 0; }
+// This is OK, but in order to see that we must instantiate f<int>, despite it
+// being in an unused default argument.
+void g1(char c = {f1<int>()}) {} // expected-warning {{braces around scalar}}
+
+// This is formally ill-formed, but we choose to not trigger instantiation here
+// (at least, not until g2 is actually called in a way that uses the default
+// argument).
+template<typename T> int f2() { return T::error; }
+void g2(int c = f2<int>()) {}
+
+// FIXME: Provide a note pointing at the first use of the default argument?
+template<typename T> int f3() { return T::error; } // expected-error {{no members}}
+void g3(int c = f3<int>()) {} // expected-note {{in instantiation of}}
+void use_g3() { g3(); }
+#endif