Tyker created this revision.
Tyker added a reviewer: rsmith.
Herald added a reviewer: martong.
Herald added a reviewer: shafik.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

this patch adds support for the explicit bool specifier.

added parsing for explicit bool specifier in ParseDecl.cpp
adapted storage of explicit specifier in AST and DeclSpec.

  was boolean value not it is a PointerIntPair with a flag and a potential 
expression.
  was stored in every function declaration. now it is stored only in 
CXXConstructorDecl, CXXDeductionGuideDecl and CXXConversionDecl.

adpated AddOverloadCandidate, AddTemplateOverloadCandidate, 
AddConversionCandidate and AddTemplateConversionCandidate
adapted template instatiation to instantiate explicit bool expressions.
to receive a boolean idicating if function resolved to be explicit should be 
removed.
adapted Serialization, ASTMatchers, ASTComparator and ASTPrinter
added test for semantic and serialization.

this patch is not yet complete. i still need to check the interaction with CTAD 
and deduction guides.
and add more tests for AST operations. but i wanted first feedback.

perhaps this patch should be splitted in smaller patchs. but making each patch 
testable as a standalone may be tricky.


Repository:
  rC Clang

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,336 @@
+// 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,7 +2442,7 @@
       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();
   }
@@ -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->hasExplicitSpecifer())
+      ExplicitSpecInfoPrinter(CDecl->getExplicitSpecifier(), Out, Policy,
+                              Indentation);
+    if (ConversionDecl && ConversionDecl->hasExplicitSpecifer())
+      ExplicitSpecInfoPrinter(ConversionDecl->getExplicitSpecifier(), Out,
+                              Policy, Indentation);
+    if (GuideDecl && GuideDecl->hasExplicitSpecifer())
+      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 specfier 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.hasExplicitSpecifer();
 }
 
 /// 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 hasExplicitSpecifer() 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 hasExplicitSpecifer() 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 hasExplicitSpecifer() 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