Tyker updated this revision to Diff 195973.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60934/new/

https://reviews.llvm.org/D60934

Files:
  clang/include/clang/AST/Decl.h
  clang/include/clang/AST/DeclBase.h
  clang/include/clang/AST/DeclCXX.h
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Basic/Specifiers.h
  clang/include/clang/Sema/DeclSpec.h
  clang/include/clang/Sema/Overload.h
  clang/include/clang/Sema/Sema.h
  clang/include/clang/Serialization/ASTReader.h
  clang/lib/AST/ASTImporter.cpp
  clang/lib/AST/ASTStructuralEquivalence.cpp
  clang/lib/AST/Decl.cpp
  clang/lib/AST/DeclCXX.cpp
  clang/lib/AST/DeclPrinter.cpp
  clang/lib/Parse/ParseDecl.cpp
  clang/lib/Sema/DeclSpec.cpp
  clang/lib/Sema/SemaCodeComplete.cpp
  clang/lib/Sema/SemaDecl.cpp
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaLambda.cpp
  clang/lib/Sema/SemaLookup.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/lib/Serialization/ASTReaderDecl.cpp
  clang/lib/Serialization/ASTWriterDecl.cpp
  clang/test/PCH/cxx-explicit-spec.cpp
  clang/test/SemaCXX/cxx2a-explicit-bool.cpp
  clang/test/SemaCXX/explicit.cpp

Index: clang/test/SemaCXX/explicit.cpp
===================================================================
--- clang/test/SemaCXX/explicit.cpp
+++ clang/test/SemaCXX/explicit.cpp
@@ -1,4 +1,6 @@
 // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
+
 namespace Constructor {
 struct A {
   A(int);
@@ -183,7 +185,8 @@
     const int &copyList7 = {b};
     const int &copyList8 = {n}; // expected-error {{no viable conversion}}
   }
-  
+
+#if __cplusplus < 201707L
   void testNew()
   {
     // 5.3.4p6:
@@ -200,7 +203,8 @@
     new int[i];
     new int[ni]; // expected-error {{array size expression of type 'NotInt' requires explicit conversion to type 'int'}}
   }
-  
+#endif
+
   void testDelete()
   {
     // 5.3.5pp2:
Index: clang/test/SemaCXX/cxx2a-explicit-bool.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/cxx2a-explicit-bool.cpp
@@ -0,0 +1,335 @@
+// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify
+
+template<bool b, auto val>
+struct enable_ifv {};
+
+template<auto val>
+struct enable_ifv<true, val> {
+  static constexpr auto value = val;
+};
+
+template<typename T1, typename T2>
+struct is_same {
+    static constexpr bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+    static constexpr bool value = true;
+};
+
+namespace test0
+{
+
+template<int a>
+struct A {
+  explicit(1 << a)
+  //expected-error@-1 {{argument to explicit specifier is not a valid constant expression}}
+  //expected-note@-2 {{negative shift count -1}}
+  A(int);
+};
+
+A<-1> a(0); //expected-note {{in instantiation of template class}}
+
+template<int a>
+struct B {
+  explicit(b)
+  // expected-error@-1 {{use of undeclared identifier}}
+  // expected-note@-2 {{this expression is parsed as explicit(bool) since c++2a}}
+  B(int);
+};
+
+}
+
+namespace test1 {
+
+template<bool b>
+struct A {
+  // expected-note@-1 {{candidate constructor}}
+  // expected-note@-2 {{candidate constructor}}
+  // expected-note@-3 {{candidate function}} expected-note@-3 {{candidate function}}
+  // expected-note@-4 {{candidate function}} expected-note@-4 {{candidate function}}
+  explicit(b) A(int, int = 0);
+  // expected-note@-1 {{explicit constructor declared here}}
+  // expected-note@-2 {{explicit constructor declared here}}
+  // expected-note@-3 {{explicit constructor declared here}}
+};
+
+template<bool b>
+A<b>::A(int, int) {}
+
+void f()
+{
+  A<true> a0 = 0; // expected-error {{no viable conversion}}
+  A<true> a1( 0);
+  A<true> && a2 = 0;// expected-error {{could not bind}}
+  A<true> && a3( 0);// expected-error {{could not bind}}
+  A<true> a4{ 0};
+  A<true> && a5 = { 0};// expected-error {{chosen constructor is explicit}}
+  A<true> && a6{ 0};
+  A<true> a7 = { 0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
+
+  a0 = 0;
+  a1 = { 0}; // expected-error {{no viable overloaded '='}}
+  a2 = A<true>( 0);
+  a3 = A<true>{ 0};
+
+  A<false> c0 =  ((short)0);
+  A<false> c1( ((short)0));
+  A<false> && c2 =  ((short)0);
+  A<false> && c3( ((short)0));
+  A<false> c4{ ((short)0)};
+  A<false> && c5 = { ((short)0)};
+  A<false> && c6{ ((short)0)};
+
+  A<true> d1( 0, 0);
+  A<true> d2{ 0, 0};
+  A<true> d3 = { 0, 0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
+
+  d1 = { 0, 0}; // expected-error {{no viable overloaded '='}}
+  d2 = A<true>( 0, 0);
+  d3 = A<true>{ 0, 0};
+}
+}
+
+namespace test2 {
+
+template<bool a, typename T1>
+struct A {
+// expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}}
+// expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
+  template<typename T2>
+  explicit(a ^ is_same<T1, T2>::value)
+// expected-note@-1 {{explicit(bool) specifier resolved to true}} expected-note@-1 {{explicit(bool) specifier resolved to true}}
+  A(T2) {}
+// expected-note@-1 {{explicit constructor declared here}} expected-note@-1 {{explicit constructor declared here}}
+// expected-note@-2 {{candidate constructor ignored}} expected-note@-2 {{candidate constructor ignored}}
+// expected-note@-3 {{explicit constructor declared here}} expected-note@-3 {{explicit constructor declared here}}
+};
+
+A<true, int> a0 = 0.0; // expected-error {{no viable conversion}}
+A<true, int> a1( 0.0);
+A<true, int> && a2 = 0.0;// expected-error {{could not bind}}
+A<true, int> && a3( 0.0);// expected-error {{could not bind}}
+A<true, int> a4{ 0.0};
+A<true, int> && a5 = { 0.0};// expected-error {{chosen constructor is explicit}}
+A<true, int> && a6{ 0.0};
+A<true, int> a7 = { 0.0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
+
+A<true, int> b0 = 0;
+A<true, int> b1( 0);
+A<true, int> && b2 = 0;
+A<true, int> && b3( 0);
+A<true, int> b4{ 0};
+A<true, int> && b5 = { 0};
+A<true, int> && b6{ 0};
+A<true, int> b7 = { 0};
+
+A<true, double> c0 = 0; // expected-error {{no viable conversion}}
+A<true, double> c1( 0);
+A<true, double> && c2 = 0;// expected-error {{could not bind}}
+A<true, double> && c3( 0);// expected-error {{could not bind}}
+A<true, double> c4{ 0};
+A<true, double> && c5 = { 0};// expected-error {{chosen constructor is explicit}}
+A<true, double> && c6{ 0};
+A<true, double> c7 = { 0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
+
+}
+
+namespace test3 {
+
+template<bool a, typename T1>
+struct A {
+// expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}}
+// expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
+// expected-note@-3 {{candidate constructor}} expected-note@-3 {{candidate constructor}}
+// expected-note@-4 {{candidate constructor}} expected-note@-4 {{candidate constructor}}
+// expected-note@-5 {{candidate constructor}} expected-note@-5 {{candidate constructor}}
+  template<typename T2>
+  explicit(enable_ifv<is_same<int, T2>::value, a>::value)
+//expected-note@-1 {{explicit(bool) specifier resolved to true}}
+  A(T2) {}
+// expected-note@-1 {{substitution failure}}
+// expected-note@-2 {{substitution failure}}
+// expected-note@-3 {{substitution failure}}
+// expected-note@-4 {{substitution failure}}
+// expected-note@-5 {{candidate constructor ignored}}
+// expected-note@-6 {{explicit constructor declared here}}
+};
+
+  A<true, int> a0 = 0.0; // expected-error {{no viable conversion}}
+  A<true, int> a1( 0.0); // expected-error {{no matching constructor}}
+  A<true, int> a4{ 0.0}; // expected-error {{no matching constructor}}
+  A<true, int> a7 = { 0.0}; // expected-error {{no matching constructor}}
+
+  A<true, int> b0 = 0; // expected-error {{no viable conversion}}
+  A<true, int> b1( 0);
+  A<true, int> b4{ 0};
+  A<true, int> b7 = { 0}; // expected-error {{chosen constructor is explicit}}
+
+  A<false, int> c0 = 0;
+  A<false, int> c1( 0);
+  A<false, int> c4{ 0};
+  A<false, int> c7 = { 0};
+}
+
+namespace test4 {
+
+template<bool a>
+struct A {
+  explicit(a) operator int ();
+};
+
+template<bool a>
+A<a>::operator int() {
+  return 0;
+}
+
+A<true> A_true;
+A<false> A_false;
+
+
+int ai0 = A<true>(); // expected-error {{no viable conversion}}
+const int& ai1 = A<true>(); // expected-error {{no viable conversion}}
+int&& ai3 = A<true>(); // expected-error {{no viable conversion}}
+int ai4 = A_true; // expected-error {{no viable conversion}}
+const int& ai5 = A_true; // expected-error {{no viable conversion}}
+
+int ai01 = {A<true>()}; // expected-error {{no viable conversion}}
+const int& ai11 = {A<true>()}; // expected-error {{no viable conversion}}
+int&& ai31 = {A<true>()}; // expected-error {{no viable conversion}}
+int ai41 = {A_true}; // expected-error {{no viable conversion}}
+const int& ai51 = {A_true}; // expected-error {{no viable conversion}}
+
+int ae0(A<true>());
+const int& ae1(A<true>());
+int&& ae3(A<true>());
+int ae4(A_true);
+const int& ae5(A_true);
+
+int bi0 = A<false>();
+const int& bi1 = A<false>();
+int&& bi3 = A<false>();
+int bi4 = A_false;
+const int& bi5 = A_false;
+
+int bi01 = {A<false>()};
+const int& bi11 = {A<false>()};
+int&& bi31 = {A<false>()};
+int bi41 = {A_false};
+const int& bi51 = {A_false};
+
+int be0(A<true>());
+const int& be1(A<true>());
+int&& be3(A<true>());
+int be4(A_true);
+const int& be5(A_true);
+
+}
+
+namespace test5 {
+
+struct B {};
+  // expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}}
+  // expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
+  // expected-note@-3 {{candidate constructor}} expected-note@-3 {{candidate constructor}}
+  // expected-note@-4 {{candidate constructor}} expected-note@-4 {{candidate constructor}}
+  // expected-note@-5 {{candidate constructor}} expected-note@-5 {{candidate constructor}}
+
+template<bool a>
+struct A {
+  template<typename T2>
+  explicit(enable_ifv<is_same<B, T2>::value, a>::value)
+  // expected-note@-1 {{explicit(bool) specifier resolved to true}}
+  // expected-note@-2 {{explicit(bool) specifier resolved to true}}
+  // expected-note@-3 {{explicit(bool) specifier resolved to true}}
+  // expected-note@-4 {{explicit(bool) specifier resolved to true}}
+  // expected-note@-5 {{explicit(bool) specifier resolved to true}}
+  operator T2() { return T2(); };
+  // expected-note@-1 {{substitution failure}}
+  // expected-note@-2 {{substitution failure}}
+  // expected-note@-3 {{substitution failure}}
+  // expected-note@-4 {{substitution failure}}
+  // expected-note@-5 {{substitution failure}}
+  // expected-note@-6 {{substitution failure}}
+  // expected-note@-7 {{substitution failure}}
+  // expected-note@-8 {{substitution failure}}
+  // expected-note@-9 {{substitution failure}}
+  // expected-note@-10 {{substitution failure}}
+  // expected-note@-11 {{substitution failure}}
+  // expected-note@-12 {{substitution failure}}
+  // expected-note@-13 {{substitution failure}}
+  // expected-note@-14 {{substitution failure}}
+  // expected-note@-15 {{substitution failure}}
+  // expected-note@-16 {{candidate conversion}}
+  // expected-note@-17 {{candidate conversion}}
+  // expected-note@-18 {{candidate conversion}}
+  // expected-note@-19 {{candidate conversion}}
+  // expected-note@-20 {{candidate conversion}}
+};
+
+A<false> A_false;
+A<true> A_true;
+
+int ai0 = A<true>(); // expected-error {{no viable conversion}}
+const int& ai1 = A<true>(); // expected-error {{no viable conversion}}
+int&& ai3 = A<true>(); // expected-error {{no viable conversion}}
+int ai4 = A_false; // expected-error {{no viable conversion}}
+const int& ai5 = A_false; // expected-error {{no viable conversion}}
+
+int ae0{A<true>()};  // expected-error {{no viable conversion}}
+const int& ae1{A<true>()};  // expected-error {{no viable conversion}}
+int&& ae3{A<true>()};  // expected-error {{no viable conversion}}
+int ae4{A_true};  // expected-error {{no viable conversion}}
+const int& ae5{A_true};  // expected-error {{no viable conversion}}
+
+int ap0((A<true>()));  // expected-error {{no viable conversion}}
+const int& ap1((A<true>()));  // expected-error {{no viable conversion}}
+int&& ap3((A<true>()));  // expected-error {{no viable conversion}}
+int ap4(A_true);  // expected-error {{no viable conversion}}
+const int& ap5(A_true);  // expected-error {{no viable conversion}}
+
+B b0 = A<true>(); // expected-error {{no viable conversion}}
+const B & b1 = A<true>(); // expected-error {{no viable conversion}}
+B && b3 = A<true>(); // expected-error {{no viable conversion}}
+B b4 = A_true; // expected-error {{no viable conversion}}
+const B & b5 = A_true; // expected-error {{no viable conversion}}
+
+B be0(A<true>());
+const B& be1(A<true>());
+B&& be3(A<true>());
+B be4(A_true);
+const B& be5(A_true);
+
+B c0 = A<false>();
+const B & c1 = A<false>();
+B && c3 = A<false>();
+B c4 = A_false;
+const B & c5 = A_false;
+
+}
+
+namespace test6 {
+
+template<typename T>
+struct A {
+  // expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}}
+  template<typename ... Ts>
+  explicit((is_same<T, Ts>::value && ...))
+  // expected-note@-1 {{explicit(bool) specifier resolved to true}}
+  A(Ts...);
+  // expected-note@-1 {{candidate constructor}}
+  // expected-note@-2 {{explicit constructor}}
+};
+
+template<typename T>
+template<typename ... Ts>
+A<T>::A(Ts ...) {}
+
+A<int> a0 = 0; // expected-error {{no viable conversion}}
+A<int> a1( 0, 1);
+A<int> a4{ 0, 1};
+A<int> a7 = { 0, 1}; // expected-error {{chosen constructor is explicit}}
+
+}
+
Index: clang/test/PCH/cxx-explicit-spec.cpp
===================================================================
--- /dev/null
+++ clang/test/PCH/cxx-explicit-spec.cpp
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -std=c++11 -emit-pch %s -o %t
+// RUN: %clang_cc1 -std=c++11 -include-pch %t -verify %s
+
+// RUN: %clang_cc1 -std=c++2a -DCXX2A -emit-pch %s -o %t-cxx2a
+// RUN: %clang_cc1 -std=c++2a -DCXX2A -include-pch %t-cxx2a -verify %s
+
+namespace B1 {
+
+#ifndef HEADER_BLOCK1
+#define HEADER_BLOCK1
+
+struct A {
+  explicit A(int) {}
+};
+
+#else
+// expected-note@-5 {{candidate}}
+// expected-note@-6 {{candidate}}
+
+A a = 0; // expected-error {{no viable conversion}}
+
+#endif
+
+} // B1
+
+#ifdef CXX2A
+
+namespace B2 {
+
+#ifndef HEADER_BLOCK2
+#define HEADER_BLOCK2
+
+template<bool b>
+struct B {
+  explicit(b) B(int) {}
+};
+
+#else
+
+// expected-note@-6 {{candidate}}
+// expected-note@-7 {{candidate}}
+
+B<true> b = 0; // expected-error {{no viable conversion}}
+B<false> b1 = 0;
+
+#endif
+
+} // B2
+
+#endif
Index: clang/lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterDecl.cpp
+++ clang/lib/Serialization/ASTWriterDecl.cpp
@@ -535,7 +535,6 @@
   Record.push_back(static_cast<int>(D->getStorageClass())); // FIXME: stable encoding
   Record.push_back(D->isInlineSpecified());
   Record.push_back(D->isInlined());
-  Record.push_back(D->isExplicitSpecified());
   Record.push_back(D->isVirtualAsWritten());
   Record.push_back(D->isPure());
   Record.push_back(D->hasInheritedPrototype());
@@ -629,6 +628,11 @@
 }
 
 void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+  if (D->getExplicitSpecifier().getPointer()) {
+    Record.push_back(ESF_unresolved);
+    Record.AddStmt(D->getExplicitSpecifier().getPointer());
+  } else
+    Record.push_back(D->getExplicitFlag());
   VisitFunctionDecl(D);
   Record.push_back(D->isCopyDeductionCandidate());
   Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
@@ -1321,6 +1325,11 @@
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+  if (D->getExplicitSpecifier().getPointer()) {
+    Record.push_back(ESF_unresolved);
+    Record.AddStmt(D->getExplicitSpecifier().getPointer());
+  } else
+    Record.push_back(D->getExplicitFlag());
   if (auto Inherited = D->getInheritedConstructor()) {
     Record.AddDeclRef(Inherited.getShadowDecl());
     Record.AddDeclRef(Inherited.getConstructor());
@@ -1347,6 +1356,11 @@
 }
 
 void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
+  if (D->getExplicitSpecifier().getPointer()) {
+    Record.push_back(ESF_unresolved);
+    Record.AddStmt(D->getExplicitSpecifier().getPointer());
+  } else
+    Record.push_back(D->getExplicitFlag());
   VisitCXXMethodDecl(D);
   Code = serialization::DECL_CXX_CONVERSION;
 }
@@ -2143,7 +2157,6 @@
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified
-  Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitSpecified
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten
   Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
   Abv->Add(BitCodeAbbrevOp(0));                         // HasInheritedProto
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -858,7 +858,6 @@
   FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
   FD->setInlineSpecified(Record.readInt());
   FD->setImplicitlyInline(Record.readInt());
-  FD->setExplicitSpecified(Record.readInt());
   FD->setVirtualAsWritten(Record.readInt());
   FD->setPure(Record.readInt());
   FD->setHasInheritedPrototype(Record.readInt());
@@ -1967,6 +1966,7 @@
 }
 
 void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+  D->setExplicitSpecifier(Record.readExplicitSpec());
   VisitFunctionDecl(D);
   D->setIsCopyDeductionCandidate(Record.readInt());
 }
@@ -1992,6 +1992,7 @@
 void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
   // We need the inherited constructor information to merge the declaration,
   // so we have to read it before we call VisitCXXMethodDecl.
+  D->setExplicitSpecifier(Record.readExplicitSpec());
   if (D->isInheritingConstructor()) {
     auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>();
     auto *Ctor = ReadDeclAs<CXXConstructorDecl>();
@@ -2017,6 +2018,7 @@
 }
 
 void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
+  D->setExplicitSpecifier(Record.readExplicitSpec());
   VisitCXXMethodDecl(D);
 }
 
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -366,6 +366,43 @@
                                    Attr.getSpellingListIndex());
 }
 
+static ExplicitSpecInfo
+instantiateExplicitSpecifier(Sema &S,
+                             const MultiLevelTemplateArgumentList &TemplateArgs,
+                             ExplicitSpecInfo ESI, FunctionDecl *New) {
+  if (!ESI.getPointer())
+    return ESI;
+  ExplicitSpecInfo Result(nullptr, ESF_unresolved);
+  Expr *OldCond = ESI.getPointer();
+  Expr *Cond = nullptr;
+  {
+    Sema::ContextRAII SwitchContext(S, New);
+    EnterExpressionEvaluationContext Unevaluated(
+        S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+    ExprResult SubstResult = S.SubstExpr(OldCond, TemplateArgs);
+    if (SubstResult.isInvalid())
+      return Result;
+    Cond = SubstResult.getAs<Expr>();
+  }
+  if (!Cond->isTypeDependent()) {
+    ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
+    if (Converted.isInvalid())
+      return Result;
+    Cond = Converted.get();
+  }
+  SmallVector<PartialDiagnosticAt, 8> Diags;
+  if (OldCond->isValueDependent() && !Cond->isValueDependent() &&
+      !Expr::isPotentialConstantExprUnevaluated(Cond, New, Diags)) {
+    S.Diag(ESI.getPointer()->getBeginLoc(),
+           diag::err_explicit_needs_constant_expression);
+    for (const auto &P : Diags)
+      S.Diag(P.first, P.second);
+    return Result;
+  }
+  Result.setPointerAndInt(Cond, ESI.getInt());
+  return Result;
+}
+
 static void instantiateDependentAMDGPUWavesPerEUAttr(
     Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
     const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
@@ -1727,8 +1764,9 @@
   FunctionDecl *Function;
   if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
     Function = CXXDeductionGuideDecl::Create(
-      SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
-      NameInfo, T, TInfo, D->getSourceRange().getEnd());
+        SemaRef.Context, DC, D->getInnerLocStart(),
+        DGuide->getExplicitSpecifier(), NameInfo, T, TInfo,
+        D->getSourceRange().getEnd());
     if (DGuide->isCopyDeductionCandidate())
       cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
     Function->setAccess(D->getAccess());
@@ -2035,11 +2073,12 @@
   DeclarationNameInfo NameInfo
     = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
   if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
-    Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
-                                        StartLoc, NameInfo, T, TInfo,
-                                        Constructor->isExplicit(),
-                                        Constructor->isInlineSpecified(),
-                                        false, Constructor->isConstexpr());
+    Method = CXXConstructorDecl::Create(
+        SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
+        instantiateExplicitSpecifier(SemaRef, TemplateArgs,
+                                     Constructor->getExplicitSpecifier(),
+                                     Constructor),
+        Constructor->isInlineSpecified(), false, Constructor->isConstexpr());
     Method->setRangeEnd(Constructor->getEndLoc());
   } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
     Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
@@ -2050,7 +2089,10 @@
   } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
     Method = CXXConversionDecl::Create(
         SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
-        Conversion->isInlineSpecified(), Conversion->isExplicit(),
+        Conversion->isInlineSpecified(),
+        instantiateExplicitSpecifier(SemaRef, TemplateArgs,
+                                     Conversion->getExplicitSpecifier(),
+                                     Conversion),
         Conversion->isConstexpr(), Conversion->getEndLoc());
   } else {
     StorageClass SC = D->isStatic() ? SC_Static : SC_None;
@@ -2251,7 +2293,8 @@
 }
 
 Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
-  return VisitCXXMethodDecl(D);
+  Decl *Result = VisitCXXMethodDecl(D);
+  return Result;
 }
 
 Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -1109,7 +1109,7 @@
     if (DS.isVirtualSpecified())
       EmitDiag(DS.getVirtualSpecLoc());
 
-    if (DS.isExplicitSpecified())
+    if (DS.hasExplicitSpecifier())
       EmitDiag(DS.getExplicitSpecLoc());
 
     if (DS.isNoreturnSpecified())
@@ -1789,8 +1789,8 @@
       return nullptr;
     TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
 
-    return buildDeductionGuide(TemplateParams, CD->isExplicit(), NewTInfo,
-                               CD->getBeginLoc(), CD->getLocation(),
+    return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(),
+                               NewTInfo, CD->getBeginLoc(), CD->getLocation(),
                                CD->getEndLoc());
   }
 
@@ -1819,8 +1819,9 @@
       Params.push_back(NewParam);
     }
 
-    return buildDeductionGuide(Template->getTemplateParameters(), false, TSI,
-                               Loc, Loc, Loc);
+    return buildDeductionGuide(Template->getTemplateParameters(),
+                               ExplicitSpecInfo(nullptr, ESF_resolved_false),
+                               TSI, Loc, Loc, Loc);
   }
 
 private:
@@ -1970,7 +1971,7 @@
   }
 
   NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
-                                 bool Explicit, TypeSourceInfo *TInfo,
+                                 ExplicitSpecInfo ESI, TypeSourceInfo *TInfo,
                                  SourceLocation LocStart, SourceLocation Loc,
                                  SourceLocation LocEnd) {
     DeclarationNameInfo Name(DeductionGuideName, Loc);
@@ -1979,8 +1980,8 @@
 
     // Build the implicit deduction guide template.
     auto *Guide =
-        CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit,
-                                      Name, TInfo->getType(), TInfo, LocEnd);
+        CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ESI, Name,
+                                      TInfo->getType(), TInfo, LocEnd);
     Guide->setImplicit();
     Guide->setParams(Params);
 
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -3232,7 +3232,7 @@
 
     bool Usable = !Info.Constructor->isInvalidDecl() &&
                   S.isInitListConstructor(Info.Constructor) &&
-                  (AllowExplicit || !Info.Constructor->isExplicit());
+                  (AllowExplicit || Info.Constructor->isMaybeNotExplicit());
     if (Usable) {
       // If the first argument is (a reference to) the target type,
       // suppress conversions.
@@ -3241,10 +3241,13 @@
       if (Info.ConstructorTmpl)
         S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
                                        /*ExplicitArgs*/ nullptr, From,
-                                       CandidateSet, SuppressUserConversions);
+                                       CandidateSet, SuppressUserConversions,
+                                       /*PartialOverloading*/ false,
+                                       AllowExplicit);
       else
         S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From,
-                               CandidateSet, SuppressUserConversions);
+                               CandidateSet, SuppressUserConversions,
+                               /*PartialOverloading*/ false, AllowExplicit);
     }
   }
 
@@ -3352,7 +3355,8 @@
 
         bool Usable = !Info.Constructor->isInvalidDecl();
         if (ListInitializing)
-          Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit());
+          Usable = Usable &&
+                   (AllowExplicit || Info.Constructor->isMaybeNotExplicit());
         else
           Usable = Usable &&
                    Info.Constructor->isConvertingConstructor(AllowExplicit);
@@ -3371,13 +3375,15 @@
             S.AddTemplateOverloadCandidate(
                 Info.ConstructorTmpl, Info.FoundDecl,
                 /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
-                CandidateSet, SuppressUserConversions);
+                CandidateSet, SuppressUserConversions,
+                /*PartialOverloading*/ false, AllowExplicit);
           else
             // Allow one user-defined conversion when user specifies a
             // From->ToType conversion via an static cast (c-style, etc).
             S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
                                    llvm::makeArrayRef(Args, NumArgs),
-                                   CandidateSet, SuppressUserConversions);
+                                   CandidateSet, SuppressUserConversions,
+                                   /*PartialOverloading*/ false, AllowExplicit);
         }
       }
     }
@@ -3407,16 +3413,15 @@
         else
           Conv = cast<CXXConversionDecl>(D);
 
-        if (AllowExplicit || !Conv->isExplicit()) {
+        if (AllowExplicit || Conv->isMaybeNotExplicit()) {
           if (ConvTemplate)
-            S.AddTemplateConversionCandidate(ConvTemplate, FoundDecl,
-                                             ActingContext, From, ToType,
-                                             CandidateSet,
-                                             AllowObjCConversionOnExplicit);
+            S.AddTemplateConversionCandidate(
+                ConvTemplate, FoundDecl, ActingContext, From, ToType,
+                CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
           else
-            S.AddConversionCandidate(Conv, FoundDecl, ActingContext,
-                                     From, ToType, CandidateSet,
-                                     AllowObjCConversionOnExplicit);
+            S.AddConversionCandidate(
+                Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
+                AllowObjCConversionOnExplicit, AllowExplicit);
         }
       }
     }
@@ -4397,7 +4402,7 @@
 
     // If this is an explicit conversion, and we're not allowed to consider
     // explicit conversions, skip it.
-    if (!AllowExplicit && Conv->isExplicit())
+    if (!AllowExplicit && Conv->getExplicitFlag() == ESF_resolved_true)
       continue;
 
     if (AllowRvalues) {
@@ -4437,13 +4442,13 @@
     }
 
     if (ConvTemplate)
-      S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
-                                       Init, DeclType, CandidateSet,
-                                       /*AllowObjCConversionOnExplicit=*/false);
+      S.AddTemplateConversionCandidate(
+          ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
+          /*AllowObjCConversionOnExplicit=*/false, AllowExplicit);
     else
-      S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
-                               DeclType, CandidateSet,
-                               /*AllowObjCConversionOnExplicit=*/false);
+      S.AddConversionCandidate(
+          Conv, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
+          /*AllowObjCConversionOnExplicit=*/false, AllowExplicit);
   }
 
   bool HadMultipleCandidates = (CandidateSet.size() > 1);
@@ -5722,12 +5727,13 @@
 
     if (ConvTemplate)
       SemaRef.AddTemplateConversionCandidate(
-        ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
-        /*AllowObjCConversionOnExplicit=*/false);
+          ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
+          /*AllowObjCConversionOnExplicit=*/false, /*AllowExplicit*/ true);
     else
       SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,
                                      ToType, CandidateSet,
-                                     /*AllowObjCConversionOnExplicit=*/false);
+                                     /*AllowObjCConversionOnExplicit=*/false,
+                                     /*AllowExplicit*/ true);
   }
 }
 
@@ -5979,13 +5985,11 @@
 /// \param PartialOverloading true if we are performing "partial" overloading
 /// based on an incomplete set of function arguments. This feature is used by
 /// code completion.
-void Sema::AddOverloadCandidate(FunctionDecl *Function,
-                                DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
-                                OverloadCandidateSet &CandidateSet,
-                                bool SuppressUserConversions,
-                                bool PartialOverloading, bool AllowExplicit,
-                                ADLCallKind IsADLCandidate,
-                                ConversionSequenceList EarlyConversions) {
+void Sema::AddOverloadCandidate(
+    FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
+    OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
+    bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
+    ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) {
   const FunctionProtoType *Proto
     = dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
   assert(Proto && "Functions without a prototype cannot be overloaded");
@@ -6142,13 +6146,11 @@
       // (13.3.3.1) that converts that argument to the corresponding
       // parameter of F.
       QualType ParamType = Proto->getParamType(ArgIdx);
-      Candidate.Conversions[ArgIdx]
-        = TryCopyInitialization(*this, Args[ArgIdx], ParamType,
-                                SuppressUserConversions,
-                                /*InOverloadResolution=*/true,
-                                /*AllowObjCWritebackConversion=*/
-                                  getLangOpts().ObjCAutoRefCount,
-                                AllowExplicit);
+      Candidate.Conversions[ArgIdx] = TryCopyInitialization(
+          *this, Args[ArgIdx], ParamType, SuppressUserConversions,
+          /*InOverloadResolution=*/true,
+          /*AllowObjCWritebackConversion=*/
+          getLangOpts().ObjCAutoRefCount, AllowExplicitConversions);
       if (Candidate.Conversions[ArgIdx].isBad()) {
         Candidate.Viable = false;
         Candidate.FailureKind = ovl_fail_bad_conversion;
@@ -6162,6 +6164,21 @@
     }
   }
 
+  //  Constructor = dyn_cast<CXXConstructorDecl>(Function);
+  if (!AllowExplicit) {
+    CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(Function);
+    ExplicitSpecInfo ESI(nullptr, ESF_resolved_false);
+    if (Constructor)
+      ESI = Constructor->getExplicitSpecifier();
+    if (Conversion)
+      ESI = Conversion->getExplicitSpecifier();
+    if (ESI.getInt() != ESF_resolved_false) {
+      Candidate.Viable = false;
+      Candidate.FailureKind = ovl_fail_explicit_resolved;
+      return;
+    }
+  }
+
   if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_enable_if;
@@ -6361,7 +6378,6 @@
     if (!EIA->getCond()->EvaluateWithSubstitution(
             Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)))
       return EIA;
-
     if (!Result.isInt() || !Result.getInt().getBoolValue())
       return EIA;
   }
@@ -6751,7 +6767,7 @@
     FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
     TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
     OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
-    bool PartialOverloading, ADLCallKind IsADLCandidate) {
+    bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) {
   if (!CandidateSet.isNewCandidate(FunctionTemplate))
     return;
 
@@ -6800,9 +6816,10 @@
   // Add the function template specialization produced by template argument
   // deduction as a candidate.
   assert(Specialization && "Missing function template specialization?");
-  AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet,
-                       SuppressUserConversions, PartialOverloading,
-                       /*AllowExplicit*/ false, IsADLCandidate, Conversions);
+  AddOverloadCandidate(
+      Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
+      PartialOverloading, AllowExplicit,
+      /*AllowExplicitConversions*/ false, IsADLCandidate, Conversions);
 }
 
 /// Check that implicit conversion sequences can be formed for each argument
@@ -6907,14 +6924,11 @@
 /// and ToType is the type that we're eventually trying to convert to
 /// (which may or may not be the same type as the type that the
 /// conversion function produces).
-void
-Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
-                             DeclAccessPair FoundDecl,
-                             CXXRecordDecl *ActingContext,
-                             Expr *From, QualType ToType,
-                             OverloadCandidateSet& CandidateSet,
-                             bool AllowObjCConversionOnExplicit,
-                             bool AllowResultConversion) {
+void Sema::AddConversionCandidate(
+    CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
+    CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
+    OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
+    bool AllowExplicit, bool AllowResultConversion) {
   assert(!Conversion->getDescribedFunctionTemplate() &&
          "Conversion function templates use AddTemplateConversionCandidate");
   QualType ConvType = Conversion->getConversionType().getNonReferenceType();
@@ -7073,6 +7087,12 @@
            "Can only end up with a standard conversion sequence or failure");
   }
 
+  if (!AllowExplicit && Conversion->getExplicitFlag() != ESF_resolved_false) {
+    Candidate.Viable = false;
+    Candidate.FailureKind = ovl_fail_explicit_resolved;
+    return;
+  }
+
   if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
     Candidate.Viable = false;
     Candidate.FailureKind = ovl_fail_enable_if;
@@ -7092,14 +7112,11 @@
 /// to deduce the template arguments of the conversion function
 /// template from the type that we are converting to (C++
 /// [temp.deduct.conv]).
-void
-Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
-                                     DeclAccessPair FoundDecl,
-                                     CXXRecordDecl *ActingDC,
-                                     Expr *From, QualType ToType,
-                                     OverloadCandidateSet &CandidateSet,
-                                     bool AllowObjCConversionOnExplicit,
-                                     bool AllowResultConversion) {
+void Sema::AddTemplateConversionCandidate(
+    FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
+    CXXRecordDecl *ActingDC, Expr *From, QualType ToType,
+    OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
+    bool AllowExplicit, bool AllowResultConversion) {
   assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
          "Only conversion function templates permitted here");
 
@@ -7129,7 +7146,7 @@
   assert(Specialization && "Missing function template specialization?");
   AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
                          CandidateSet, AllowObjCConversionOnExplicit,
-                         AllowResultConversion);
+                         AllowExplicit, AllowResultConversion);
 }
 
 /// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -8983,12 +9000,14 @@
 
       AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
                            /*SupressUserConversions=*/false, PartialOverloading,
-                           /*AllowExplicit=*/false, ADLCallKind::UsesADL);
+                           /*AllowExplicitConversions*/ false,
+                           /*AllowExplicit*/ false, ADLCallKind::UsesADL);
     } else {
-      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl,
-                                   ExplicitTemplateArgs, Args, CandidateSet,
-                                   /*SupressUserConversions=*/false,
-                                   PartialOverloading, ADLCallKind::UsesADL);
+      AddTemplateOverloadCandidate(
+          cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
+          CandidateSet,
+          /*SupressUserConversions=*/false, PartialOverloading,
+          /*AllowExplicit*/ false, ADLCallKind::UsesADL);
     }
   }
 }
@@ -10319,6 +10338,21 @@
       << Attr->getCond()->getSourceRange() << Attr->getMessage();
 }
 
+static void DiagnoseFailedExplicitBool(Sema &S, OverloadCandidate *Cand) {
+  auto *Constructor = dyn_cast<CXXConstructorDecl>(Cand->Function);
+  S.Diag(Cand->Function->getLocation(), diag::note_ovl_candidate_ignored)
+      << (Constructor ? "constructor" : "conversion function");
+  Expr *BoolExpr;
+  if (Constructor)
+    BoolExpr = Constructor->getExplicitSpecifier().getPointer();
+  else
+    BoolExpr = cast<CXXConversionDecl>(Cand->Function)
+                   ->getExplicitSpecifier()
+                   .getPointer();
+  assert(BoolExpr && "substitution failure should be handled before");
+  S.Diag(BoolExpr->getBeginLoc(), diag::note_explicit_bool_resolved_to_true);
+}
+
 static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
   FunctionDecl *Callee = Cand->Function;
 
@@ -10403,6 +10437,9 @@
   case ovl_fail_enable_if:
     return DiagnoseFailedEnableIfAttr(S, Cand);
 
+  case ovl_fail_explicit_resolved:
+    return DiagnoseFailedExplicitBool(S, Cand);
+
   case ovl_fail_ext_disabled:
     return DiagnoseOpenCLExtensionDisabled(S, Cand);
 
@@ -12938,8 +12975,11 @@
 
       // Microsoft supports direct constructor calls.
       if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
-        AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(),
-                             Args, CandidateSet);
+        AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args,
+                             CandidateSet,
+                             /*SuppressUserConversions*/ false,
+                             /*PartialOverloading*/ false,
+                             /*AllowExplicit*/ true);
       } else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
         // If explicit template arguments were provided, we can't call a
         // non-template member function.
Index: clang/lib/Sema/SemaLookup.cpp
===================================================================
--- clang/lib/Sema/SemaLookup.cpp
+++ clang/lib/Sema/SemaLookup.cpp
@@ -3020,10 +3020,15 @@
                            llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
       else if (CtorInfo)
         AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
-                             llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+                             llvm::makeArrayRef(&Arg, NumArgs), OCS,
+                             /*SuppressUserConversions*/ true,
+                             /*PartialOverloading*/ false,
+                             /*AllowExplcit*/ true);
       else
         AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
-                             true);
+                             /*SuppressUserConversions*/ true,
+                             /*PartialOverloading*/ false,
+                             /*AllowExplcit*/ true);
     } else if (FunctionTemplateDecl *Tmpl =
                  dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
       if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
Index: clang/lib/Sema/SemaLambda.cpp
===================================================================
--- clang/lib/Sema/SemaLambda.cpp
+++ clang/lib/Sema/SemaLambda.cpp
@@ -1304,7 +1304,7 @@
   CXXConversionDecl *Conversion = CXXConversionDecl::Create(
       S.Context, Class, Loc,
       DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
-      /*isInline=*/true, /*isExplicit=*/false,
+      /*isInline=*/true, ExplicitSpecInfo(nullptr, ESF_resolved_false),
       /*isConstexpr=*/S.getLangOpts().CPlusPlus17,
       CallOperator->getBody()->getEndLoc());
   Conversion->setAccess(AS_public);
@@ -1391,7 +1391,7 @@
   CXXConversionDecl *Conversion = CXXConversionDecl::Create(
       S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
       S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
-      /*isInline=*/true, /*isExplicit=*/false,
+      /*isInline=*/true, ExplicitSpecInfo(nullptr, ESF_resolved_false),
       /*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
   Conversion->setAccess(AS_public);
   Conversion->setImplicit(true);
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -21,6 +21,7 @@
 #include "clang/Sema/Initialization.h"
 #include "clang/Sema/Lookup.h"
 #include "clang/Sema/SemaInternal.h"
+#include "clang/Sema/Template.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -3740,7 +3741,8 @@
     if (!Info.Constructor || Info.Constructor->isInvalidDecl())
       continue;
 
-    if (!AllowExplicit && Info.Constructor->isExplicit())
+    if (!AllowExplicit &&
+        Info.Constructor->getExplicitFlag() == ESF_resolved_true)
       continue;
 
     if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor))
@@ -3763,9 +3765,10 @@
          hasCopyOrMoveCtorParam(S.Context, Info));
 
     if (Info.ConstructorTmpl)
-      S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
-                                     /*ExplicitArgs*/ nullptr, Args,
-                                     CandidateSet, SuppressUserConversions);
+      S.AddTemplateOverloadCandidate(
+          Info.ConstructorTmpl, Info.FoundDecl,
+          /*ExplicitArgs*/ nullptr, Args, CandidateSet, SuppressUserConversions,
+          /*PartialOverloading=*/false, AllowExplicit);
     else {
       // C++ [over.match.copy]p1:
       //   - When initializing a temporary to be bound to the first parameter
@@ -3779,8 +3782,8 @@
                                hasCopyOrMoveCtorParam(S.Context, Info);
       S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
                              CandidateSet, SuppressUserConversions,
-                             /*PartialOverloading=*/false,
-                             /*AllowExplicit=*/AllowExplicitConv);
+                             /*PartialOverloading=*/false, AllowExplicit,
+                             AllowExplicitConv);
     }
   }
 
@@ -3813,16 +3816,18 @@
         else
           Conv = cast<CXXConversionDecl>(D);
 
-        if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
+        if ((AllowExplicit && !CopyInitializing) ||
+            Conv->isMaybeNotExplicit()) {
           if (ConvTemplate)
-            S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
-                                             ActingDC, Initializer, DestType,
-                                             CandidateSet, AllowExplicit,
-                                             /*AllowResultConversion*/false);
+            S.AddTemplateConversionCandidate(
+                ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+                CandidateSet, AllowExplicit, AllowExplicit,
+                /*AllowResultConversion*/ false);
           else
             S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
                                      DestType, CandidateSet, AllowExplicit,
-                                     /*AllowResultConversion*/false);
+                                     AllowExplicit,
+                                     /*AllowResultConversion*/ false);
         }
       }
     }
@@ -4368,14 +4373,16 @@
       if (!Info.Constructor->isInvalidDecl() &&
           Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
         if (Info.ConstructorTmpl)
-          S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
-                                         /*ExplicitArgs*/ nullptr,
-                                         Initializer, CandidateSet,
-                                         /*SuppressUserConversions=*/true);
+          S.AddTemplateOverloadCandidate(
+              Info.ConstructorTmpl, Info.FoundDecl,
+              /*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
+              /*SuppressUserConversions=*/true,
+              /*PartialOverloading*/ false, AllowExplicitCtors);
         else
-          S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
-                                 Initializer, CandidateSet,
-                                 /*SuppressUserConversions=*/true);
+          S.AddOverloadCandidate(
+              Info.Constructor, Info.FoundDecl, Initializer, CandidateSet,
+              /*SuppressUserConversions=*/true,
+              /*PartialOverloading*/ false, AllowExplicitCtors);
       }
     }
   }
@@ -4409,18 +4416,18 @@
       // FIXME: Do we need to make sure that we only consider conversion
       // candidates with reference-compatible results? That might be needed to
       // break recursion.
-      if ((AllowExplicitConvs || !Conv->isExplicit()) &&
-          (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
+      if ((AllowRValues ||
+           Conv->getConversionType()->isLValueReferenceType()) &&
+          (AllowExplicitConvs || Conv->isMaybeNotExplicit())) {
         if (ConvTemplate)
-          S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
-                                           ActingDC, Initializer,
-                                           DestType, CandidateSet,
-                                           /*AllowObjCConversionOnExplicit=*/
-                                             false);
+          S.AddTemplateConversionCandidate(
+              ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+              CandidateSet,
+              /*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
         else
-          S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
-                                   Initializer, DestType, CandidateSet,
-                                   /*AllowObjCConversionOnExplicit=*/false);
+          S.AddConversionCandidate(
+              Conv, I.getPair(), ActingDC, Initializer, DestType, CandidateSet,
+              /*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
       }
     }
   }
@@ -4992,18 +4999,19 @@
         auto Info = getConstructorInfo(D);
         if (!Info.Constructor)
           continue;
-
         if (!Info.Constructor->isInvalidDecl() &&
             Info.Constructor->isConvertingConstructor(AllowExplicit)) {
           if (Info.ConstructorTmpl)
-            S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
-                                           /*ExplicitArgs*/ nullptr,
-                                           Initializer, CandidateSet,
-                                           /*SuppressUserConversions=*/true);
+            S.AddTemplateOverloadCandidate(
+                Info.ConstructorTmpl, Info.FoundDecl,
+                /*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
+                /*SuppressUserConversions=*/true,
+                /*PartialOverloading*/ false, AllowExplicit);
           else
             S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
                                    Initializer, CandidateSet,
-                                   /*SuppressUserConversions=*/true);
+                                   /*SuppressUserConversions=*/true,
+                                   /*PartialOverloading*/ false, AllowExplicit);
         }
       }
     }
@@ -5036,14 +5044,14 @@
         else
           Conv = cast<CXXConversionDecl>(D);
 
-        if (AllowExplicit || !Conv->isExplicit()) {
+        if (AllowExplicit || Conv->isMaybeNotExplicit()) {
           if (ConvTemplate)
-            S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
-                                             ActingDC, Initializer, DestType,
-                                             CandidateSet, AllowExplicit);
+            S.AddTemplateConversionCandidate(
+                ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
+                CandidateSet, AllowExplicit, AllowExplicit);
           else
-            S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
-                                     Initializer, DestType, CandidateSet,
+            S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
+                                     DestType, CandidateSet, AllowExplicit,
                                      AllowExplicit);
         }
       }
@@ -9351,7 +9359,7 @@
       //   The converting constructors of T are candidate functions.
       if (Kind.isCopyInit() && !ListInit) {
         // Only consider converting constructors.
-        if (GD->isExplicit())
+        if (!GD->isMaybeNotExplicit())
           continue;
 
         // When looking for a converting constructor, deduction guides that
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -661,10 +661,11 @@
   // deduction guide have different explicitness. For now at least we simply
   // reject any case where the explicitness changes.
   auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New);
-  if (NewGuide && NewGuide->isExplicitSpecified() !=
-                      cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) {
+  if (NewGuide && (NewGuide->getExplicitFlag() !=
+                       cast<CXXDeductionGuideDecl>(Old)->getExplicitFlag() ||
+                   NewGuide->getExplicitFlag() == ESF_unresolved)) {
     Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
-      << NewGuide->isExplicitSpecified();
+        << NewGuide->isExplicit();
     Diag(Old->getLocation(), diag::note_previous_declaration);
   }
 
@@ -8630,7 +8631,7 @@
     R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
 
   // C++0x explicit conversion operators.
-  if (DS.isExplicitSpecified())
+  if (DS.hasExplicitSpecifier())
     Diag(DS.getExplicitSpecLoc(),
          getLangOpts().CPlusPlus11
              ? diag::warn_cxx98_compat_explicit_conversion_functions
@@ -10855,6 +10856,28 @@
 };
 }
 
+ExprResult Sema::ActOnExplicitBoolSpecifier(SourceLocation Loc,
+                                            ExplicitSpecFlag &Flag,
+                                            Expr *ExplicitExpr) {
+  ExprResult Converted =
+      CheckBooleanCondition(Loc, ExplicitExpr, /*isConstexpr=*/true);
+  if (Converted.isInvalid())
+    return Converted;
+
+  if (Converted.get()->isValueDependent()) {
+    Flag = ESF_unresolved;
+    return Converted;
+  }
+
+  llvm::APSInt Result;
+  Converted = VerifyIntegerConstantExpression(
+      Converted.get(), &Result, diag::err_noexcept_needs_constant_expression,
+      /*AllowFold*/ false);
+  if (!Converted.isInvalid())
+    Flag = Result.getBoolValue() ? ESF_resolved_true : ESF_resolved_false;
+  return Converted;
+}
+
 static Sema::ImplicitExceptionSpecification
 ComputeDefaultedSpecialMemberExceptionSpec(
     Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
@@ -11003,9 +11026,9 @@
     = Context.DeclarationNames.getCXXConstructorName(ClassType);
   DeclarationNameInfo NameInfo(Name, ClassLoc);
   CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
-      Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(),
-      /*TInfo=*/nullptr, /*isExplicit=*/false, /*isInline=*/true,
-      /*isImplicitlyDeclared=*/true, Constexpr);
+      Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(),
+      /*TInfo=*/nullptr, ExplicitSpecInfo(nullptr, ESF_resolved_false),
+      /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr);
   DefaultCon->setAccess(AS_public);
   DefaultCon->setDefaulted();
 
@@ -11124,7 +11147,7 @@
 
   CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
       Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
-      BaseCtor->isExplicit(), /*Inline=*/true,
+      BaseCtor->getExplicitSpecifier(), /*Inline=*/true,
       /*ImplicitlyDeclared=*/true, Constexpr,
       InheritedConstructor(Shadow, BaseCtor));
   if (Shadow->isInvalidDecl())
@@ -12577,8 +12600,8 @@
   //   member of its class.
   CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
       Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
-      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
-      Constexpr);
+      ExplicitSpecInfo(nullptr, ESF_resolved_false), /*isInline=*/true,
+      /*isImplicitlyDeclared=*/true, Constexpr);
   CopyConstructor->setAccess(AS_public);
   CopyConstructor->setDefaulted();
 
@@ -12707,8 +12730,8 @@
   //   member of its class.
   CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
       Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
-      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
-      Constexpr);
+      ExplicitSpecInfo(nullptr, ESF_resolved_false), /*isInline=*/true,
+      /*isImplicitlyDeclared=*/true, Constexpr);
   MoveConstructor->setAccess(AS_public);
   MoveConstructor->setDefaulted();
 
Index: clang/lib/Sema/SemaDecl.cpp
===================================================================
--- clang/lib/Sema/SemaDecl.cpp
+++ clang/lib/Sema/SemaDecl.cpp
@@ -5688,7 +5688,7 @@
     Diag(DS.getVirtualSpecLoc(),
          diag::err_virtual_non_function);
 
-  if (DS.isExplicitSpecified())
+  if (DS.hasExplicitSpecifier())
     Diag(DS.getExplicitSpecLoc(),
          diag::err_explicit_non_function);
 
@@ -7952,7 +7952,7 @@
     return NewFD;
   }
 
-  bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+  ExplicitSpecInfo ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
   bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
 
   // Check that the return type is not an abstract class type.
@@ -7972,7 +7972,7 @@
     R = SemaRef.CheckConstructorDeclarator(D, R, SC);
     return CXXConstructorDecl::Create(
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
-        TInfo, isExplicit, isInline,
+        TInfo, ExplicitSpecifier, isInline,
         /*isImplicitlyDeclared=*/false, isConstexpr);
 
   } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
@@ -8017,13 +8017,13 @@
     IsVirtualOkay = true;
     return CXXConversionDecl::Create(
         SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
-        TInfo, isInline, isExplicit, isConstexpr, SourceLocation());
+        TInfo, isInline, ExplicitSpecifier, isConstexpr, SourceLocation());
 
   } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
     SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
 
     return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
-                                         isExplicit, NameInfo, R, TInfo,
+                                         ExplicitSpecifier, NameInfo, R, TInfo,
                                          D.getEndLoc());
   } else if (DC->isRecord()) {
     // If the name of the function is the same as the name of the record,
@@ -8384,7 +8384,7 @@
   if (getLangOpts().CPlusPlus) {
     bool isInline = D.getDeclSpec().isInlineSpecified();
     bool isVirtual = D.getDeclSpec().isVirtualSpecified();
-    bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+    bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
     bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
     isFriend = D.getDeclSpec().isFriendSpecified();
     if (isFriend && !isInline && D.isFunctionDefinition()) {
@@ -8563,24 +8563,36 @@
       }
     }
 
-    // C++ [dcl.fct.spec]p6:
-    //  The explicit specifier shall be used only in the declaration of a
+    // C++ [dcl.fct.spec]p3:
+    //  The explicit-specifier shall be used only in the declaration of a
     //  constructor or conversion function within its class definition;
-    //  see 12.3.1 and 12.3.2.
-    if (isExplicit && !NewFD->isInvalidDecl() &&
-        !isa<CXXDeductionGuideDecl>(NewFD)) {
-      if (!CurContext->isRecord()) {
-        // 'explicit' was specified outside of the class.
-        Diag(D.getDeclSpec().getExplicitSpecLoc(),
-             diag::err_explicit_out_of_class)
-          << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
-      } else if (!isa<CXXConstructorDecl>(NewFD) &&
-                 !isa<CXXConversionDecl>(NewFD)) {
-        // 'explicit' was specified on a function that wasn't a constructor
-        // or conversion function.
-        Diag(D.getDeclSpec().getExplicitSpecLoc(),
-             diag::err_explicit_non_ctor_or_conv_function)
-          << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
+    //  see [class.conv.ctor] and [class.conv.fct].
+    if (hasExplicit && !NewFD->isInvalidDecl()) {
+      if (!isa<CXXDeductionGuideDecl>(NewFD)) {
+        if (!CurContext->isRecord()) {
+          // 'explicit' was specified outside of the class.
+          Diag(D.getDeclSpec().getExplicitSpecLoc(),
+               diag::err_explicit_out_of_class)
+              << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
+        } else if (!isa<CXXConstructorDecl>(NewFD) &&
+                   !isa<CXXConversionDecl>(NewFD)) {
+          // 'explicit' was specified on a function that wasn't a constructor
+          // or conversion function.
+          Diag(D.getDeclSpec().getExplicitSpecLoc(),
+               diag::err_explicit_non_ctor_or_conv_function)
+              << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
+        }
+      } else
+          // the explicit specifier in a deduction guide cannot have a constant
+          // expression. althought an explicit specifier with a constant
+          // expression can still appear on a deduction guide when it is
+          // generated from a constructor
+          if (D.getDeclSpec().getExplicitSpecifier().getPointer()) {
+        Diag(D.getDeclSpec().getExplicitSpecParenLoc(),
+             diag::err_deduction_guide_explicit_bool);
+        CXXDeductionGuideDecl *Guide = cast<CXXDeductionGuideDecl>(NewFD);
+        Guide->setExplicitSpecifier(
+            ExplicitSpecInfo(nullptr, ESF_resolved_true));
       }
     }
 
@@ -9142,6 +9154,16 @@
     NewFD->setType(R);
   }
 
+  if (auto *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
+    Constructor->setExplicitSpecifier(
+        cast<CXXConstructorDecl>(Constructor->getCanonicalDecl())
+            ->getExplicitSpecifier());
+  } else if (auto *Conversion = dyn_cast<CXXConversionDecl>(NewFD)) {
+    Conversion->setExplicitSpecifier(
+        cast<CXXConversionDecl>(Conversion->getCanonicalDecl())
+            ->getExplicitSpecifier());
+  }
+
   // If there's a #pragma GCC visibility in scope, and this isn't a class
   // member, set the visibility of this function.
   if (!DC->isRecord() && NewFD->isExternallyVisible())
Index: clang/lib/Sema/SemaCodeComplete.cpp
===================================================================
--- clang/lib/Sema/SemaCodeComplete.cpp
+++ clang/lib/Sema/SemaCodeComplete.cpp
@@ -4964,13 +4964,15 @@
       AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
                            CandidateSet,
                            /*SuppressUsedConversions=*/false,
-                           /*PartialOverloading=*/true);
+                           /*PartialOverloading=*/true,
+                           /*AllowExplicit*/ true);
     } else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
       AddTemplateOverloadCandidate(
           FTD, DeclAccessPair::make(FTD, C->getAccess()),
           /*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,
           /*SuppressUsedConversions=*/false,
-          /*PartialOverloading=*/true);
+          /*PartialOverloading=*/true,
+          /*AllowExplicit*/ true);
     }
   }
 
Index: clang/lib/Sema/DeclSpec.cpp
===================================================================
--- clang/lib/Sema/DeclSpec.cpp
+++ clang/lib/Sema/DeclSpec.cpp
@@ -445,7 +445,7 @@
   if (hasTypeSpecifier())
     Res |= PQ_TypeSpecifier;
 
-  if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified ||
+  if (FS_inline_specified || FS_virtual_specified || hasExplicitSpecifier() ||
       FS_noreturn_specified || FS_forceinline_specified)
     Res |= PQ_FunctionSpecifier;
   return Res;
@@ -944,17 +944,27 @@
 }
 
 bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc,
-                                       const char *&PrevSpec,
-                                       unsigned &DiagID) {
+                                       const char *&PrevSpec, unsigned &DiagID,
+                                       ExplicitSpecFlag ExplicitState,
+                                       Expr *ExplicitExpr,
+                                       SourceLocation ParenLoc) {
+  assert((ExplicitState != ESF_unresolved || ExplicitExpr) &&
+         "ExplicitExpr can't be null if the state is ESF_resolved_false or "
+         "ESF_unresolved");
   // 'explicit explicit' is ok, but warn as this is likely not what the user
   // intended.
-  if (FS_explicit_specified) {
+  // multiple explicit specifier doesn't appear to be still allwoded in c++2a
+  // from the c++2a draft :
+  // Each decl-specifier shall appear at most once in a complete
+  // decl-specifier-seq, except that long may appear twice.
+  if (hasExplicitSpecifier()) {
     DiagID = diag::warn_duplicate_declspec;
     PrevSpec = "explicit";
     return true;
   }
-  FS_explicit_specified = true;
+  FS_explicit_specifier = ExplicitSpecifierInfo(ExplicitExpr, ExplicitState);
   FS_explicitLoc = Loc;
+  FS_explicitParenLoc = ParenLoc;
   return false;
 }
 
@@ -1293,7 +1303,7 @@
   //   The explicit specifier shall be used only in the declaration of
   //   a constructor or conversion function within its class
   //   definition;
-  if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) {
+  if (isFriendSpecified() && (isVirtualSpecified() || hasExplicitSpecifier())) {
     StringRef Keyword;
     SourceLocation SCLoc;
 
@@ -1309,7 +1319,8 @@
     S.Diag(SCLoc, diag::err_friend_decl_spec)
       << Keyword << Hint;
 
-    FS_virtual_specified = FS_explicit_specified = false;
+    FS_virtual_specified = false;
+    FS_explicit_specifier = ExplicitSpecifierInfo(nullptr, ESF_resolved_false);
     FS_virtualLoc = FS_explicitLoc = SourceLocation();
   }
 
Index: clang/lib/Parse/ParseDecl.cpp
===================================================================
--- clang/lib/Parse/ParseDecl.cpp
+++ clang/lib/Parse/ParseDecl.cpp
@@ -2442,12 +2442,12 @@
       Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
     if (DS.isVirtualSpecified())
       Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
-    if (DS.isExplicitSpecified())
+    if (DS.hasExplicitSpecifier())
       Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
     DS.ClearFunctionSpecs();
   }
 
-  // Issue diagnostic and remove constexpr specfier if present.
+  // Issue diagnostic and remove constexpr specifier if present.
   if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) {
     Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
     DS.ClearConstexprSpec();
@@ -3515,9 +3515,39 @@
         isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
       }
       break;
-    case tok::kw_explicit:
-      isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID);
+    case tok::kw_explicit: {
+      SourceLocation ExplicitLoc = Loc;
+      SourceLocation ParenLoc;
+      SourceLocation ExplicitEnd = Tok.getLastLoc();
+      ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
+      ExplicitSpecFlag ExplicitFlag = ESF_resolved_true;
+      if (GetLookAheadToken(1).is(tok::l_paren)) {
+        if (getLangOpts().CPlusPlus2a) {
+          ConsumeToken(); // kw_explicit
+          ParenLoc = ConsumeParen();
+          BalancedDelimiterTracker T(*this, tok::l_paren);
+          ExplicitExpr = ParseConstantExpression();
+          if (ExplicitExpr.isUsable())
+            ExplicitExpr = Actions.ActOnExplicitBoolSpecifier(
+                ExplicitLoc, ExplicitFlag, ExplicitExpr.get());
+          if (!ExplicitExpr.isUsable()) {
+            Diag(ParenLoc, diag::note_explicit_bool_breaking_change_cxx2a)
+                << FixItHint::CreateReplacement(
+                       SourceRange(ExplicitLoc, ExplicitEnd), "explicit(true)");
+            if (Tok.is(tok::r_paren))
+              ConsumeParen();
+            // TODO improve parsing recovery by skipping declaration
+            return;
+          }
+        } else
+          Diag(GetLookAheadToken(1).getLocation(),
+               diag::warn_explicit_bool_breaking_change_cxx17);
+      }
+      isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
+                                             ExplicitFlag, ExplicitExpr.get(),
+                                             ParenLoc);
       break;
+    }
     case tok::kw__Noreturn:
       if (!getLangOpts().C11)
         Diag(Loc, diag::ext_c11_noreturn);
Index: clang/lib/AST/DeclPrinter.cpp
===================================================================
--- clang/lib/AST/DeclPrinter.cpp
+++ clang/lib/AST/DeclPrinter.cpp
@@ -552,6 +552,23 @@
   }
 }
 
+static void ExplicitSpecInfoPrinter(ExplicitSpecInfo ESI,
+                                    llvm::raw_ostream &Out,
+                                    PrintingPolicy &Policy,
+                                    unsigned Indentation) {
+  std::string Proto = "explicit";
+  if (ESI.getPointer()) {
+    Proto += "(";
+    llvm::raw_string_ostream EOut(Proto);
+    ESI.getPointer()->printPretty(EOut, nullptr, Policy, Indentation);
+    EOut.flush();
+    Proto += EOut.str();
+    Proto += ")";
+  }
+  Proto += " ";
+  Out << Proto;
+}
+
 void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
   if (!D->getDescribedFunctionTemplate() &&
       !D->isFunctionTemplateSpecialization())
@@ -582,10 +599,15 @@
     if (D->isVirtualAsWritten()) Out << "virtual ";
     if (D->isModulePrivate())    Out << "__module_private__ ";
     if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
-    if ((CDecl && CDecl->isExplicitSpecified()) ||
-        (ConversionDecl && ConversionDecl->isExplicitSpecified()) ||
-        (GuideDecl && GuideDecl->isExplicitSpecified()))
-      Out << "explicit ";
+    if (CDecl && CDecl->hasExplicitSpecifier())
+      ExplicitSpecInfoPrinter(CDecl->getExplicitSpecifier(), Out, Policy,
+                              Indentation);
+    if (ConversionDecl && ConversionDecl->hasExplicitSpecifier())
+      ExplicitSpecInfoPrinter(ConversionDecl->getExplicitSpecifier(), Out,
+                              Policy, Indentation);
+    if (GuideDecl && GuideDecl->hasExplicitSpecifier())
+      ExplicitSpecInfoPrinter(GuideDecl->getExplicitSpecifier(), Out, Policy,
+                              Indentation);
   }
 
   PrintingPolicy SubPolicy(Policy);
Index: clang/lib/AST/DeclCXX.cpp
===================================================================
--- clang/lib/AST/DeclCXX.cpp
+++ clang/lib/AST/DeclCXX.cpp
@@ -1862,19 +1862,93 @@
 
 void CXXDeductionGuideDecl::anchor() {}
 
+/// Resolves the explicit specifier if possible
+/// Return true if the explicit specifier is now resolved
+static bool MaybeResolveExplicit(FunctionDecl *Decl, ExplicitSpecInfo &ESI) {
+  if (ESI.getInt() != ESF_unresolved || !ESI.getPointer())
+    return true;
+  APValue Result;
+  if (ESI.getPointer()->EvaluateWithSubstitution(
+          Result, Decl->getASTContext(), Decl, llvm::ArrayRef<Expr *>())) {
+    ESI.setInt(Result.getInt().getBoolValue() ? ESF_resolved_true
+                                              : ESF_resolved_false);
+    return true;
+  }
+  return false;
+}
+
+void CXXDeductionGuideDecl::setExplicitSpecifier(ExplicitSpecInfo ESI) {
+  ExplicitSpecifier = ESI;
+  MaybeResolveExplicit(this, ExplicitSpecifier);
+}
+
+void CXXConversionDecl::setExplicitSpecifier(ExplicitSpecInfo ESI) {
+  ExplicitSpecifier = ESI;
+  MaybeResolveExplicit(this, ExplicitSpecifier);
+}
+
+void CXXConstructorDecl::setExplicitSpecifier(ExplicitSpecInfo ESI) {
+  ExplicitSpecifier = ESI;
+  MaybeResolveExplicit(this, ExplicitSpecifier);
+}
+
+/// Check for Equivalence of explicit specifiers
+/// Return True if the explicit specifier are equivalent
+static bool EquivalentExplicit(ExplicitSpecInfo First, ExplicitSpecInfo Second,
+                               const ASTContext &Ctx) {
+  if ((First.getInt() != Second.getInt() || First.getInt() == ESF_unresolved)) {
+    llvm::FoldingSetNodeID OldFSN, NewFSN;
+    if (First.getInt() == ESF_unresolved && Second.getInt() == ESF_unresolved) {
+      Second.getPointer()->Profile(OldFSN, Ctx, true);
+      First.getPointer()->Profile(NewFSN, Ctx, true);
+      if (OldFSN == NewFSN) {
+        return true;
+      }
+    } else
+      return false;
+  }
+  return true;
+}
+
+bool CXXDeductionGuideDecl::isEquivalentExplicit(ExplicitSpecInfo Other) const {
+  return EquivalentExplicit(ExplicitSpecifier, Other, getASTContext());
+}
+
+bool CXXConversionDecl::isEquivalentExplicit(ExplicitSpecInfo Other) const {
+  return EquivalentExplicit(ExplicitSpecifier, Other, getASTContext());
+}
+
+bool CXXConstructorDecl::isEquivalentExplicit(ExplicitSpecInfo Other) const {
+  return EquivalentExplicit(ExplicitSpecifier, Other, getASTContext());
+}
+
+CXXDeductionGuideDecl::CXXDeductionGuideDecl(
+    ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+    ExplicitSpecInfo ESI, const DeclarationNameInfo &NameInfo, QualType T,
+    TypeSourceInfo *TInfo, SourceLocation EndLocation)
+    : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
+                   SC_None, false, false),
+      ExplicitSpecifier(ESI) {
+  if (EndLocation.isValid())
+    setRangeEnd(EndLocation);
+  setIsCopyDeductionCandidate(false);
+  MaybeResolveExplicit(this, ExplicitSpecifier);
+}
+
 CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
-    ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit,
-    const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
-    SourceLocation EndLocation) {
-  return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit,
-                                           NameInfo, T, TInfo, EndLocation);
+    ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+    ExplicitSpecInfo ESI, const DeclarationNameInfo &NameInfo, QualType T,
+    TypeSourceInfo *TInfo, SourceLocation EndLocation) {
+  return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ESI, NameInfo, T,
+                                           TInfo, EndLocation);
 }
 
 CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
                                                                  unsigned ID) {
-  return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false,
-                                           DeclarationNameInfo(), QualType(),
-                                           nullptr, SourceLocation());
+  return new (C, ID) CXXDeductionGuideDecl(
+      C, nullptr, SourceLocation(),
+      ExplicitSpecInfo(nullptr, ESF_resolved_false), DeclarationNameInfo(),
+      QualType(), nullptr, SourceLocation());
 }
 
 void CXXMethodDecl::anchor() {}
@@ -2312,16 +2386,17 @@
 CXXConstructorDecl::CXXConstructorDecl(
     ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
-    bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared,
+    ExplicitSpecInfo ESI, bool isInline, bool isImplicitlyDeclared,
     bool isConstexpr, InheritedConstructor Inherited)
     : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
-                    SC_None, isInline, isConstexpr, SourceLocation()) {
+                    SC_None, isInline, isConstexpr, SourceLocation()),
+      ExplicitSpecifier(ESI) {
   setNumCtorInitializers(0);
   setInheritingConstructor(static_cast<bool>(Inherited));
   setImplicit(isImplicitlyDeclared);
   if (Inherited)
     *getTrailingObjects<InheritedConstructor>() = Inherited;
-  setExplicitSpecified(isExplicitSpecified);
+  MaybeResolveExplicit(this, ExplicitSpecifier);
 }
 
 void CXXConstructorDecl::anchor() {}
@@ -2332,27 +2407,25 @@
   unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited);
   auto *Result = new (C, ID, Extra) CXXConstructorDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
-      false, false, false, false, InheritedConstructor());
+      ExplicitSpecInfo(nullptr, ESF_resolved_false), false, false, false,
+      InheritedConstructor());
   Result->setInheritingConstructor(Inherited);
   return Result;
 }
 
-CXXConstructorDecl *
-CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
-                           SourceLocation StartLoc,
-                           const DeclarationNameInfo &NameInfo,
-                           QualType T, TypeSourceInfo *TInfo,
-                           bool isExplicit, bool isInline,
-                           bool isImplicitlyDeclared, bool isConstexpr,
-                           InheritedConstructor Inherited) {
+CXXConstructorDecl *CXXConstructorDecl::Create(
+    ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
+    const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+    ExplicitSpecInfo ESI, bool isInline, bool isImplicitlyDeclared,
+    bool isConstexpr, InheritedConstructor Inherited) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConstructorName &&
          "Name must refer to a constructor");
   unsigned Extra =
       additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0);
-  return new (C, RD, Extra) CXXConstructorDecl(
-      C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline,
-      isImplicitlyDeclared, isConstexpr, Inherited);
+  return new (C, RD, Extra)
+      CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ESI, isInline,
+                         isImplicitlyDeclared, isConstexpr, Inherited);
 }
 
 CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2436,7 +2509,7 @@
   //   conversion from the type of its first parameter to the type of
   //   its class. Such a constructor is called a converting
   //   constructor.
-  if (isExplicit() && !AllowExplicit)
+  if (ExplicitSpecifier.getInt() == ESF_resolved_true && !AllowExplicit)
     return false;
 
   return (getNumParams() == 0 &&
@@ -2499,29 +2572,39 @@
   }
 }
 
+CXXConversionDecl::CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD,
+                                     SourceLocation StartLoc,
+                                     const DeclarationNameInfo &NameInfo,
+                                     QualType T, TypeSourceInfo *TInfo,
+                                     bool isInline, ExplicitSpecInfo ESI,
+                                     bool isConstexpr,
+                                     SourceLocation EndLocation)
+    : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo, SC_None,
+                    isInline, isConstexpr, EndLocation),
+      ExplicitSpecifier(ESI) {
+  MaybeResolveExplicit(this, ExplicitSpecifier);
+}
+
 void CXXConversionDecl::anchor() {}
 
 CXXConversionDecl *
 CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
-  return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(),
-                                       DeclarationNameInfo(), QualType(),
-                                       nullptr, false, false, false,
-                                       SourceLocation());
+  return new (C, ID) CXXConversionDecl(
+      C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
+      false, ExplicitSpecInfo(nullptr, ESF_resolved_false), false,
+      SourceLocation());
 }
 
-CXXConversionDecl *
-CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
-                          SourceLocation StartLoc,
-                          const DeclarationNameInfo &NameInfo,
-                          QualType T, TypeSourceInfo *TInfo,
-                          bool isInline, bool isExplicit,
-                          bool isConstexpr, SourceLocation EndLocation) {
+CXXConversionDecl *CXXConversionDecl::Create(
+    ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
+    const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+    bool isInline, ExplicitSpecInfo ESI, bool isConstexpr,
+    SourceLocation EndLocation) {
   assert(NameInfo.getName().getNameKind()
          == DeclarationName::CXXConversionFunctionName &&
          "Name must refer to a conversion function");
   return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
-                                       isInline, isExplicit, isConstexpr,
-                                       EndLocation);
+                                       isInline, ESI, isConstexpr, EndLocation);
 }
 
 bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
Index: clang/lib/AST/Decl.cpp
===================================================================
--- clang/lib/AST/Decl.cpp
+++ clang/lib/AST/Decl.cpp
@@ -2661,7 +2661,6 @@
   FunctionDeclBits.SClass = S;
   FunctionDeclBits.IsInline = isInlineSpecified;
   FunctionDeclBits.IsInlineSpecified = isInlineSpecified;
-  FunctionDeclBits.IsExplicitSpecified = false;
   FunctionDeclBits.IsVirtualAsWritten = false;
   FunctionDeclBits.IsPure = false;
   FunctionDeclBits.HasInheritedPrototype = false;
Index: clang/lib/AST/ASTStructuralEquivalence.cpp
===================================================================
--- clang/lib/AST/ASTStructuralEquivalence.cpp
+++ clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -955,13 +955,14 @@
 
   if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
     auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
-    if (Constructor1->isExplicit() != Constructor2->isExplicit())
+    if (!Constructor1->isEquivalentExplicit(
+            Constructor2->getExplicitSpecifier()))
       return false;
   }
 
   if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
     auto *Conversion2 = cast<CXXConversionDecl>(Method2);
-    if (Conversion1->isExplicit() != Conversion2->isExplicit())
+    if (!Conversion1->isEquivalentExplicit(Conversion2->getExplicitSpecifier()))
       return false;
     if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
                                   Conversion2->getConversionType()))
Index: clang/lib/AST/ASTImporter.cpp
===================================================================
--- clang/lib/AST/ASTImporter.cpp
+++ clang/lib/AST/ASTImporter.cpp
@@ -3045,11 +3045,19 @@
   // Create the imported function.
   FunctionDecl *ToFunction = nullptr;
   if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
+    Expr *ExplicitExpr = nullptr;
+    if (FromConstructor->getExplicitSpecifier().getPointer()) {
+      auto Imp =
+          importSeq(FromConstructor->getExplicitSpecifier().getPointer());
+      if (!Imp)
+        return Imp.takeError();
+      std::tie(ExplicitExpr) = *Imp;
+    }
     if (GetImportedOrCreateDecl<CXXConstructorDecl>(
-        ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
-        ToInnerLocStart, NameInfo, T, TInfo,
-        FromConstructor->isExplicit(),
-        D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
+            ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
+            ToInnerLocStart, NameInfo, T, TInfo,
+            ExplicitSpecInfo(ExplicitExpr, FromConstructor->getExplicitFlag()),
+            D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
       return ToFunction;
   } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
 
@@ -3075,10 +3083,18 @@
     ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg);
   } else if (CXXConversionDecl *FromConversion =
                  dyn_cast<CXXConversionDecl>(D)) {
+    Expr *ExplicitExpr = nullptr;
+    if (FromConversion->getExplicitSpecifier().getPointer()) {
+      auto Imp = importSeq(FromConversion->getExplicitSpecifier().getPointer());
+      if (!Imp)
+        return Imp.takeError();
+      std::tie(ExplicitExpr) = *Imp;
+    }
     if (GetImportedOrCreateDecl<CXXConversionDecl>(
             ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
             ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
-            FromConversion->isExplicit(), D->isConstexpr(), SourceLocation()))
+            ExplicitSpecInfo(ExplicitExpr, FromConversion->getExplicitFlag()),
+            D->isConstexpr(), SourceLocation()))
       return ToFunction;
   } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
     if (GetImportedOrCreateDecl<CXXMethodDecl>(
@@ -3104,6 +3120,14 @@
   // Import Ctor initializers.
   if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
     if (unsigned NumInitializers = FromConstructor->getNumCtorInitializers()) {
+      Expr *ExplicitExpr = nullptr;
+      if (FromConstructor->getExplicitSpecifier().getPointer()) {
+        auto Imp =
+            importSeq(FromConstructor->getExplicitSpecifier().getPointer());
+        if (!Imp)
+          return Imp.takeError();
+        std::tie(ExplicitExpr) = *Imp;
+      }
       SmallVector<CXXCtorInitializer *, 4> CtorInitializers(NumInitializers);
       // Import first, then allocate memory and copy if there was no error.
       if (Error Err = ImportContainerChecked(
Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -2430,6 +2430,14 @@
                                                  ID);
   }
 
+  ExplicitSpecInfo readExplicitSpec() {
+    ExplicitSpecInfo ESI(nullptr, ESF_resolved_false);
+    ESI.setInt(static_cast<ExplicitSpecFlag>(readInt()));
+    if (ESI.getInt() == ESF_unresolved)
+      ESI.setPointer(readExpr());
+    return ESI;
+  }
+
   void readExceptionSpec(SmallVectorImpl<QualType> &ExceptionStorage,
                          FunctionProtoType::ExceptionSpecInfo &ESI) {
     return Reader->readExceptionSpec(*F, ExceptionStorage, ESI, Record, Idx);
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2849,6 +2849,7 @@
                             bool SuppressUserConversions = false,
                             bool PartialOverloading = false,
                             bool AllowExplicit = false,
+                            bool AllowExplicitConversion = false,
                             ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
                             ConversionSequenceList EarlyConversions = None);
   void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
@@ -2887,7 +2888,7 @@
       FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
       TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
       OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
-      bool PartialOverloading = false,
+      bool PartialOverloading = false, bool AllowExplicit = false,
       ADLCallKind IsADLCandidate = ADLCallKind::NotADL);
   bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
                                     ArrayRef<QualType> ParamTypes,
@@ -2899,20 +2900,16 @@
                                     QualType ObjectType = QualType(),
                                     Expr::Classification
                                         ObjectClassification = {});
-  void AddConversionCandidate(CXXConversionDecl *Conversion,
-                              DeclAccessPair FoundDecl,
-                              CXXRecordDecl *ActingContext,
-                              Expr *From, QualType ToType,
-                              OverloadCandidateSet& CandidateSet,
-                              bool AllowObjCConversionOnExplicit,
-                              bool AllowResultConversion = true);
-  void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
-                                      DeclAccessPair FoundDecl,
-                                      CXXRecordDecl *ActingContext,
-                                      Expr *From, QualType ToType,
-                                      OverloadCandidateSet &CandidateSet,
-                                      bool AllowObjCConversionOnExplicit,
-                                      bool AllowResultConversion = true);
+  void AddConversionCandidate(
+      CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
+      CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
+      OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
+      bool AllowExplicit, bool AllowResultConversion = true);
+  void AddTemplateConversionCandidate(
+      FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
+      CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
+      OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
+      bool AllowExplicit, bool AllowResultConversion = true);
   void AddSurrogateCandidate(CXXConversionDecl *Conversion,
                              DeclAccessPair FoundDecl,
                              CXXRecordDecl *ActingContext,
@@ -10101,6 +10098,10 @@
   ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E,
                                    bool IsConstexpr = false);
 
+  /// ActOnExplicitBoolSpecifier - Diagnose issues for explicit(bool) specifier.
+  ExprResult ActOnExplicitBoolSpecifier(SourceLocation Loc,
+                                        ExplicitSpecFlag &Flag, Expr *E);
+
   /// DiagnoseAssignmentAsCondition - Given that an expression is
   /// being used as a boolean condition, warn if it's an assignment.
   void DiagnoseAssignmentAsCondition(Expr *E);
Index: clang/include/clang/Sema/Overload.h
===================================================================
--- clang/include/clang/Sema/Overload.h
+++ clang/include/clang/Sema/Overload.h
@@ -705,6 +705,11 @@
     /// attribute disabled it.
     ovl_fail_enable_if,
 
+    /// This candidate constructor or conversion fonction required the
+    /// explicit(bool) specifier to be resolved to false during template
+    /// instantitaion but it was resolved to true
+    ovl_fail_explicit_resolved,
+
     /// This candidate was not viable because its address could not be taken.
     ovl_fail_addr_not_available,
 
Index: clang/include/clang/Sema/DeclSpec.h
===================================================================
--- clang/include/clang/Sema/DeclSpec.h
+++ clang/include/clang/Sema/DeclSpec.h
@@ -356,7 +356,6 @@
   unsigned FS_inline_specified : 1;
   unsigned FS_forceinline_specified: 1;
   unsigned FS_virtual_specified : 1;
-  unsigned FS_explicit_specified : 1;
   unsigned FS_noreturn_specified : 1;
 
   // friend-specifier
@@ -371,6 +370,14 @@
     Expr *ExprRep;
   };
 
+  /// This is shared by CXXConstructorDecl,
+  /// CXXConversionDecl, and CXXDeductionGuideDecl.
+  using ExplicitSpecifierInfo =
+      llvm::PointerIntPair<Expr *, 2, ExplicitSpecFlag>;
+
+  /// ExplicitSpecifier - Store information about explicit spicifer.
+  ExplicitSpecifierInfo FS_explicit_specifier;
+
   // attributes.
   ParsedAttributes Attrs;
 
@@ -393,6 +400,7 @@
   SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc,
       TQ_unalignedLoc;
   SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
+  SourceLocation FS_explicitParenLoc;
   SourceLocation FS_forceinlineLoc;
   SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
   SourceLocation TQ_pipeLoc;
@@ -420,31 +428,18 @@
   }
 
   DeclSpec(AttributeFactory &attrFactory)
-    : StorageClassSpec(SCS_unspecified),
-      ThreadStorageClassSpec(TSCS_unspecified),
-      SCS_extern_in_linkage_spec(false),
-      TypeSpecWidth(TSW_unspecified),
-      TypeSpecComplex(TSC_unspecified),
-      TypeSpecSign(TSS_unspecified),
-      TypeSpecType(TST_unspecified),
-      TypeAltiVecVector(false),
-      TypeAltiVecPixel(false),
-      TypeAltiVecBool(false),
-      TypeSpecOwned(false),
-      TypeSpecPipe(false),
-      TypeSpecSat(false),
-      TypeQualifiers(TQ_unspecified),
-      FS_inline_specified(false),
-      FS_forceinline_specified(false),
-      FS_virtual_specified(false),
-      FS_explicit_specified(false),
-      FS_noreturn_specified(false),
-      Friend_specified(false),
-      Constexpr_specified(false),
-      Attrs(attrFactory),
-      writtenBS(),
-      ObjCQualifiers(nullptr) {
-  }
+      : StorageClassSpec(SCS_unspecified),
+        ThreadStorageClassSpec(TSCS_unspecified),
+        SCS_extern_in_linkage_spec(false), TypeSpecWidth(TSW_unspecified),
+        TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified),
+        TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
+        TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
+        TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified),
+        FS_inline_specified(false), FS_forceinline_specified(false),
+        FS_virtual_specified(false), FS_noreturn_specified(false),
+        Friend_specified(false), Constexpr_specified(false),
+        FS_explicit_specifier(nullptr, ESF_resolved_false), Attrs(attrFactory),
+        writtenBS(), ObjCQualifiers(nullptr) {}
 
   // storage-class-specifier
   SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
@@ -570,11 +565,19 @@
     return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc;
   }
 
+  ExplicitSpecifierInfo getExplicitSpecifier() const {
+    return FS_explicit_specifier;
+  }
+
   bool isVirtualSpecified() const { return FS_virtual_specified; }
   SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; }
 
-  bool isExplicitSpecified() const { return FS_explicit_specified; }
+  bool hasExplicitSpecifier() const {
+    return FS_explicit_specifier.getInt() != ESF_resolved_false ||
+           FS_explicit_specifier.getPointer();
+  }
   SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; }
+  SourceLocation getExplicitSpecParenLoc() const { return FS_explicitParenLoc; }
 
   bool isNoreturnSpecified() const { return FS_noreturn_specified; }
   SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
@@ -586,8 +589,9 @@
     FS_forceinlineLoc = SourceLocation();
     FS_virtual_specified = false;
     FS_virtualLoc = SourceLocation();
-    FS_explicit_specified = false;
+    FS_explicit_specifier = ExplicitSpecifierInfo(nullptr, ESF_resolved_false);
     FS_explicitLoc = SourceLocation();
+    FS_explicitParenLoc = SourceLocation();
     FS_noreturn_specified = false;
     FS_noreturnLoc = SourceLocation();
   }
@@ -706,7 +710,9 @@
   bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
                               unsigned &DiagID);
   bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
-                               unsigned &DiagID);
+                               unsigned &DiagID, ExplicitSpecFlag ExplicitState,
+                               Expr *ExplicitExpr = nullptr,
+                               SourceLocation ParenLoc = SourceLocation());
   bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
                                unsigned &DiagID);
 
Index: clang/include/clang/Basic/Specifiers.h
===================================================================
--- clang/include/clang/Basic/Specifiers.h
+++ clang/include/clang/Basic/Specifiers.h
@@ -20,6 +20,15 @@
 #include "llvm/Support/ErrorHandling.h"
 
 namespace clang {
+
+  /// define the meaning of possible values of the int in ExplicitSpecifierInfo
+  /// aka llvm::PointerIntPair<Expr*, 2, ExplicitSpecFlag>
+  enum ExplicitSpecFlag {
+    ESF_resolved_false,
+    ESF_resolved_true,
+    ESF_unresolved
+  };
+  
   /// Specifies the width of a type, e.g., short, long, or long long.
   enum TypeSpecifierWidth {
     TSW_unspecified,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1340,6 +1340,9 @@
   InGroup<MicrosoftUnqualifiedFriend>;
 def err_pure_friend : Error<"friend declaration cannot have a pure-specifier">;
 
+def err_explicit_needs_constant_expression : Error<
+  "argument to explicit specifier is not a valid constant expression">;
+
 def err_invalid_base_in_interface : Error<
   "interface type cannot inherit from "
   "%select{struct|non-public interface|class}0 %1">;
@@ -2118,6 +2121,8 @@
 def err_deduction_guide_explicit_mismatch : Error<
   "deduction guide is %select{not |}0declared 'explicit' but "
   "previous declaration was%select{ not|}0">;
+def err_deduction_guide_explicit_bool : Error<
+  "explicit specifier of a deduction guide cannot depend on a constant expression">;
 def err_deduction_guide_specialized : Error<"deduction guide cannot be "
   "%select{explicitly instantiated|explicitly specialized}0">;
 def err_deduction_guide_template_not_deducible : Error<
@@ -3637,6 +3642,10 @@
     "| has different qualifiers (expected %5 but found %6)"
     "| has different exception specification}4">;
 
+def note_ovl_candidate_ignored : Note<
+    "candidate %0 ignored: cannot be explicit in this context">;
+def note_explicit_bool_resolved_to_true : Note<
+    "explicit(bool) specifier resolved to true">;
 def note_ovl_candidate_inherited_constructor : Note<
     "constructor from base class %0 inherited here">;
 def note_ovl_candidate_inherited_constructor_slice : Note<
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -33,6 +33,12 @@
 
 let CategoryName = "Parse Issue" in {
 
+def warn_explicit_bool_breaking_change_cxx17 : Warning<
+  "this expression would be parsed as explicit(bool) in C++2a">
+  , InGroup<CXXPre2aCompat>, DefaultIgnore;
+def note_explicit_bool_breaking_change_cxx2a : Note<
+  "this expression is parsed as explicit(bool) since C++2a">;
+
 def ext_empty_translation_unit : Extension<
   "ISO C requires a translation unit to contain at least one declaration">,
   InGroup<DiagGroup<"empty-translation-unit">>;
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -6122,7 +6122,7 @@
 AST_POLYMORPHIC_MATCHER(isExplicit,
                         AST_POLYMORPHIC_SUPPORTED_TYPES(CXXConstructorDecl,
                                                         CXXConversionDecl)) {
-  return Node.isExplicit();
+  return Node.hasExplicitSpecifier();
 }
 
 /// Matches function and namespace declarations that are marked with
Index: clang/include/clang/AST/DeclCXX.h
===================================================================
--- clang/include/clang/AST/DeclCXX.h
+++ clang/include/clang/AST/DeclCXX.h
@@ -1982,6 +1982,9 @@
   }
 };
 
+/// Store information needed for explicit specifier
+using ExplicitSpecInfo = llvm::PointerIntPair<Expr *, 2, ExplicitSpecFlag>;
+
 /// Represents a C++ deduction guide declaration.
 ///
 /// \code
@@ -1996,32 +1999,45 @@
   void anchor() override;
 
 private:
+  ExplicitSpecInfo ExplicitSpecifier;
   CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
-                        bool IsExplicit, const DeclarationNameInfo &NameInfo,
-                        QualType T, TypeSourceInfo *TInfo,
-                        SourceLocation EndLocation)
-      : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
-                     SC_None, false, false) {
-    if (EndLocation.isValid())
-      setRangeEnd(EndLocation);
-    setExplicitSpecified(IsExplicit);
-    setIsCopyDeductionCandidate(false);
-  }
+                        ExplicitSpecInfo ESI,
+                        const DeclarationNameInfo &NameInfo, QualType T,
+                        TypeSourceInfo *TInfo, SourceLocation EndLocation);
 
 public:
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
 
-  static CXXDeductionGuideDecl *Create(ASTContext &C, DeclContext *DC,
-                                       SourceLocation StartLoc, bool IsExplicit,
-                                       const DeclarationNameInfo &NameInfo,
-                                       QualType T, TypeSourceInfo *TInfo,
-                                       SourceLocation EndLocation);
+  static CXXDeductionGuideDecl *
+  Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
+         ExplicitSpecInfo ESI, const DeclarationNameInfo &NameInfo, QualType T,
+         TypeSourceInfo *TInfo, SourceLocation EndLocation);
 
   static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
-  /// Whether this deduction guide is explicit.
-  bool isExplicit() const { return isExplicitSpecified(); }
+  ExplicitSpecInfo getExplicitSpecifier() const { return ExplicitSpecifier; }
+
+  bool isEquivalentExplicit(ExplicitSpecInfo Other) const;
+  bool isExplicit() const {
+    assert(ExplicitSpecifier.getInt() != ESF_unresolved);
+    return ExplicitSpecifier.getInt() == ESF_resolved_true;
+  }
+
+  bool hasExplicitSpecifier() const {
+    return ExplicitSpecifier.getInt() != ESF_resolved_false ||
+           ExplicitSpecifier.getPointer();
+  }
+
+  void setExplicitSpecifier(ExplicitSpecInfo ESI);
+
+  bool isMaybeNotExplicit() const {
+    return ExplicitSpecifier.getInt() != ESF_resolved_true;
+  }
+
+  ExplicitSpecFlag getExplicitFlag() const {
+    return ExplicitSpecifier.getInt();
+  }
 
   /// Get the template for which this guide performs deduction.
   TemplateDecl *getDeducedTemplate() const {
@@ -2499,10 +2515,11 @@
   /// The arguments used to initialize the base or member.
   LazyCXXCtorInitializersPtr CtorInitializers;
 
+  ExplicitSpecInfo ExplicitSpecifier;
+
   CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
-                     const DeclarationNameInfo &NameInfo,
-                     QualType T, TypeSourceInfo *TInfo,
-                     bool isExplicitSpecified, bool isInline,
+                     const DeclarationNameInfo &NameInfo, QualType T,
+                     TypeSourceInfo *TInfo, ExplicitSpecInfo ESI, bool isInline,
                      bool isImplicitlyDeclared, bool isConstexpr,
                      InheritedConstructor Inherited);
 
@@ -2518,7 +2535,7 @@
   static CXXConstructorDecl *
   Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
-         bool isExplicit, bool isInline, bool isImplicitlyDeclared,
+         ExplicitSpecInfo ESI, bool isInline, bool isImplicitlyDeclared,
          bool isConstexpr,
          InheritedConstructor Inherited = InheritedConstructor());
 
@@ -2592,9 +2609,27 @@
     CtorInitializers = Initializers;
   }
 
-  /// Whether this function is explicit.
+  ExplicitSpecInfo getExplicitSpecifier() const { return ExplicitSpecifier; }
+
+  bool isEquivalentExplicit(ExplicitSpecInfo Other) const;
   bool isExplicit() const {
-    return getCanonicalDecl()->isExplicitSpecified();
+    assert(ExplicitSpecifier.getInt() != ESF_unresolved);
+    return ExplicitSpecifier.getInt() == ESF_resolved_true;
+  }
+
+  bool hasExplicitSpecifier() const {
+    return ExplicitSpecifier.getInt() != ESF_resolved_false ||
+           ExplicitSpecifier.getPointer();
+  }
+
+  void setExplicitSpecifier(ExplicitSpecInfo ESI);
+
+  bool isMaybeNotExplicit() const {
+    return ExplicitSpecifier.getInt() != ESF_resolved_true;
+  }
+
+  ExplicitSpecFlag getExplicitFlag() const {
+    return ExplicitSpecifier.getInt();
   }
 
   /// Determine whether this constructor is a delegating constructor.
@@ -2773,34 +2808,45 @@
 /// };
 /// \endcode
 class CXXConversionDecl : public CXXMethodDecl {
+  ExplicitSpecInfo ExplicitSpecifier;
   CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
                     const DeclarationNameInfo &NameInfo, QualType T,
-                    TypeSourceInfo *TInfo, bool isInline,
-                    bool isExplicitSpecified, bool isConstexpr,
-                    SourceLocation EndLocation)
-      : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
-                      SC_None, isInline, isConstexpr, EndLocation) {
-    setExplicitSpecified(isExplicitSpecified);
-  }
-
+                    TypeSourceInfo *TInfo, bool isInline, ExplicitSpecInfo ESI,
+                    bool isConstexpr, SourceLocation EndLocation);
   void anchor() override;
 
 public:
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
 
-  static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
-                                   SourceLocation StartLoc,
-                                   const DeclarationNameInfo &NameInfo,
-                                   QualType T, TypeSourceInfo *TInfo,
-                                   bool isInline, bool isExplicit,
-                                   bool isConstexpr,
-                                   SourceLocation EndLocation);
+  static CXXConversionDecl *
+  Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
+         const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
+         bool isInline, ExplicitSpecInfo ESI, bool isConstexpr,
+         SourceLocation EndLocation);
   static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
-  /// Whether this function is explicit.
+  ExplicitSpecInfo getExplicitSpecifier() const { return ExplicitSpecifier; }
+
+  bool isEquivalentExplicit(ExplicitSpecInfo Other) const;
   bool isExplicit() const {
-    return getCanonicalDecl()->isExplicitSpecified();
+    assert(ExplicitSpecifier.getInt() != ESF_unresolved);
+    return ExplicitSpecifier.getInt() == ESF_resolved_true;
+  }
+
+  bool hasExplicitSpecifier() const {
+    return ExplicitSpecifier.getInt() != ESF_resolved_false ||
+           ExplicitSpecifier.getPointer();
+  }
+
+  void setExplicitSpecifier(ExplicitSpecInfo ESI);
+
+  bool isMaybeNotExplicit() const {
+    return ExplicitSpecifier.getInt() != ESF_resolved_true;
+  }
+
+  ExplicitSpecFlag getExplicitFlag() const {
+    return ExplicitSpecifier.getInt();
   }
 
   /// Returns the type that this conversion function is converting to.
Index: clang/include/clang/AST/DeclBase.h
===================================================================
--- clang/include/clang/AST/DeclBase.h
+++ clang/include/clang/AST/DeclBase.h
@@ -1475,10 +1475,6 @@
     uint64_t IsInline : 1;
     uint64_t IsInlineSpecified : 1;
 
-    /// This is shared by CXXConstructorDecl,
-    /// CXXConversionDecl, and CXXDeductionGuideDecl.
-    uint64_t IsExplicitSpecified : 1;
-
     uint64_t IsVirtualAsWritten : 1;
     uint64_t IsPure : 1;
     uint64_t HasInheritedPrototype : 1;
Index: clang/include/clang/AST/Decl.h
===================================================================
--- clang/include/clang/AST/Decl.h
+++ clang/include/clang/AST/Decl.h
@@ -2354,16 +2354,6 @@
   /// that was defined in the class body.
   bool isInlined() const { return FunctionDeclBits.IsInline; }
 
-  /// Whether this function is marked as explicit explicitly.
-  bool isExplicitSpecified() const {
-    return FunctionDeclBits.IsExplicitSpecified;
-  }
-
-  /// State that this function is marked as explicit explicitly.
-  void setExplicitSpecified(bool ExpSpec = true) {
-    FunctionDeclBits.IsExplicitSpecified = ExpSpec;
-  }
-
   bool isInlineDefinitionExternallyVisible() const;
 
   bool isMSExternInline() const;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to