r360311 - [c++20] Add support for explicit(bool), as described in P0892R2.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed May 8 20:59:22 PDT 2019


Author: rsmith
Date: Wed May  8 20:59:21 2019
New Revision: 360311

URL: http://llvm.org/viewvc/llvm-project?rev=360311&view=rev
Log:
[c++20] Add support for explicit(bool), as described in P0892R2.

Patch by Tyker!

Differential Revision: https://reviews.llvm.org/D60934

Added:
    cfe/trunk/test/PCH/cxx-explicit-specifier.cpp
    cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
    cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/Specifiers.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/Overload.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/include/clang/Serialization/ASTReader.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/AST/DeclPrinter.cpp
    cfe/trunk/lib/Frontend/InitPreprocessor.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/DeclSpec.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaLambda.cpp
    cfe/trunk/lib/Sema/SemaLookup.cpp
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp
    cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp
    cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp
    cfe/trunk/test/SemaCXX/cxx2a-compat.cpp
    cfe/trunk/test/SemaCXX/explicit.cpp
    cfe/trunk/unittests/AST/Language.cpp
    cfe/trunk/unittests/AST/Language.h
    cfe/trunk/unittests/AST/MatchVerifier.h
    cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp
    cfe/trunk/www/cxx_status.html

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed May  8 20:59:21 2019
@@ -2369,16 +2369,6 @@ public:
   /// 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;

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Wed May  8 20:59:21 2019
@@ -1472,10 +1472,6 @@ class DeclContext {
     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;
@@ -1523,7 +1519,7 @@ class DeclContext {
   };
 
   /// Number of non-inherited bits in FunctionDeclBitfields.
-  enum { NumFunctionDeclBits = 25 };
+  enum { NumFunctionDeclBits = 24 };
 
   /// Stores the bits used by CXXConstructorDecl. If modified
   /// NumCXXConstructorDeclBits and the accessor
@@ -1535,17 +1531,25 @@ class DeclContext {
     /// For the bits in FunctionDeclBitfields.
     uint64_t : NumFunctionDeclBits;
 
-    /// 25 bits to fit in the remaining availible space.
+    /// 24 bits to fit in the remaining available space.
     /// Note that this makes CXXConstructorDeclBitfields take
     /// exactly 64 bits and thus the width of NumCtorInitializers
     /// will need to be shrunk if some bit is added to NumDeclContextBitfields,
     /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
-    uint64_t NumCtorInitializers : 25;
+    uint64_t NumCtorInitializers : 24;
     uint64_t IsInheritingConstructor : 1;
+
+    /// Whether this constructor has a trail-allocated explicit specifier.
+    uint64_t HasTrailingExplicitSpecifier : 1;
+    /// If this constructor does't have a trail-allocated explicit specifier.
+    /// Whether this constructor is explicit specified.
+    uint64_t IsSimpleExplicit : 1;
   };
 
   /// Number of non-inherited bits in CXXConstructorDeclBitfields.
-  enum { NumCXXConstructorDeclBits = 26 };
+  enum {
+    NumCXXConstructorDeclBits = 64 - NumDeclContextBits - NumFunctionDeclBits
+  };
 
   /// Stores the bits used by ObjCMethodDecl.
   /// If modified NumObjCMethodDeclBits and the accessor

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed May  8 20:59:21 2019
@@ -1993,6 +1993,50 @@ public:
   }
 };
 
+/// Store information needed for an explicit specifier.
+/// used by CXXDeductionGuideDecl, CXXConstructorDecl and CXXConversionDecl.
+class ExplicitSpecifier {
+  llvm::PointerIntPair<Expr *, 2, ExplicitSpecKind> ExplicitSpec{
+      nullptr, ExplicitSpecKind::ResolvedFalse};
+
+public:
+  ExplicitSpecifier() = default;
+  ExplicitSpecifier(Expr *Expression, ExplicitSpecKind Kind)
+      : ExplicitSpec(Expression, Kind) {}
+  ExplicitSpecKind getKind() const { return ExplicitSpec.getInt(); }
+  const Expr *getExpr() const { return ExplicitSpec.getPointer(); }
+  Expr *getExpr() { return ExplicitSpec.getPointer(); }
+
+  /// Return true if the ExplicitSpecifier isn't defaulted.
+  bool isSpecified() const {
+    return ExplicitSpec.getInt() != ExplicitSpecKind::ResolvedFalse ||
+           ExplicitSpec.getPointer();
+  }
+
+  /// Check for Equivalence of explicit specifiers.
+  /// Return True if the explicit specifier are equivalent false otherwise.
+  bool isEquivalent(const ExplicitSpecifier Other) const;
+  /// Return true if the explicit specifier is already resolved to be explicit.
+  bool isExplicit() const {
+    return ExplicitSpec.getInt() == ExplicitSpecKind::ResolvedTrue;
+  }
+  /// Return true if the ExplicitSpecifier isn't valid.
+  /// This state occurs after a substitution failures.
+  bool isInvalid() const {
+    return ExplicitSpec.getInt() == ExplicitSpecKind::Unresolved &&
+           !ExplicitSpec.getPointer();
+  }
+  void setKind(ExplicitSpecKind Kind) { ExplicitSpec.setInt(Kind); }
+  void setExpr(Expr *E) { ExplicitSpec.setPointer(E); }
+  // getFromDecl - retrieve the explicit specifier in the given declaration.
+  // if the given declaration has no explicit. the returned explicit specifier
+  // is defaulted. .isSpecified() will be false.
+  static ExplicitSpecifier getFromDecl(FunctionDecl *Function);
+  static ExplicitSpecifier Invalid() {
+    return ExplicitSpecifier(nullptr, ExplicitSpecKind::Unresolved);
+  }
+};
+
 /// Represents a C++ deduction guide declaration.
 ///
 /// \code
@@ -2008,31 +2052,36 @@ class CXXDeductionGuideDecl : public Fun
 
 private:
   CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
-                        bool IsExplicit, const DeclarationNameInfo &NameInfo,
-                        QualType T, TypeSourceInfo *TInfo,
-                        SourceLocation EndLocation)
+                        ExplicitSpecifier ES,
+                        const DeclarationNameInfo &NameInfo, QualType T,
+                        TypeSourceInfo *TInfo, SourceLocation EndLocation)
       : FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
-                     SC_None, false, false) {
+                     SC_None, false, false),
+        ExplicitSpec(ES) {
     if (EndLocation.isValid())
       setRangeEnd(EndLocation);
-    setExplicitSpecified(IsExplicit);
     setIsCopyDeductionCandidate(false);
   }
 
+  ExplicitSpecifier ExplicitSpec;
+  void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; }
+
 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,
+         ExplicitSpecifier ES, 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(); }
+  ExplicitSpecifier getExplicitSpecifier() { return ExplicitSpec; }
+  const ExplicitSpecifier getExplicitSpecifier() const { return ExplicitSpec; }
+
+  /// Return true if the declartion is already resolved to be explicit.
+  bool isExplicit() const { return ExplicitSpec.isExplicit(); }
 
   /// Get the template for which this guide performs deduction.
   TemplateDecl *getDeducedTemplate() const {
@@ -2501,7 +2550,8 @@ public:
 /// \endcode
 class CXXConstructorDecl final
     : public CXXMethodDecl,
-      private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor> {
+      private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor,
+                                    ExplicitSpecifier> {
   // This class stores some data in DeclContext::CXXConstructorDeclBits
   // to save some space. Use the provided accessors to access it.
 
@@ -2511,28 +2561,74 @@ class CXXConstructorDecl final
   LazyCXXCtorInitializersPtr CtorInitializers;
 
   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, ExplicitSpecifier ES, bool isInline,
                      bool isImplicitlyDeclared, bool isConstexpr,
                      InheritedConstructor Inherited);
 
   void anchor() override;
 
+  size_t numTrailingObjects(OverloadToken<InheritedConstructor>) const {
+    return CXXConstructorDeclBits.IsInheritingConstructor;
+  }
+  size_t numTrailingObjects(OverloadToken<ExplicitSpecifier>) const {
+    return CXXConstructorDeclBits.HasTrailingExplicitSpecifier;
+  }
+
+  ExplicitSpecifier getExplicitSpecifierInternal() const {
+    if (CXXConstructorDeclBits.HasTrailingExplicitSpecifier)
+      return *getCanonicalDecl()->getTrailingObjects<ExplicitSpecifier>();
+    return ExplicitSpecifier(
+        nullptr, getCanonicalDecl()->CXXConstructorDeclBits.IsSimpleExplicit
+                     ? ExplicitSpecKind::ResolvedTrue
+                     : ExplicitSpecKind::ResolvedFalse);
+  }
+
+  void setExplicitSpecifier(ExplicitSpecifier ES) {
+    assert((!ES.getExpr() ||
+            CXXConstructorDeclBits.HasTrailingExplicitSpecifier) &&
+           "cannot set this explicit specifier. no trail-allocated space for "
+           "explicit");
+    if (ES.getExpr())
+      *getCanonicalDecl()->getTrailingObjects<ExplicitSpecifier>() = ES;
+    else
+      CXXConstructorDeclBits.IsSimpleExplicit = ES.isExplicit();
+  }
+
+  enum TraillingAllocKind {
+    TAKInheritsConstructor = 1,
+    TAKHasTailExplicit = 1 << 1,
+  };
+
+  uint64_t getTraillingAllocKind() const {
+    return numTrailingObjects(OverloadToken<InheritedConstructor>()) |
+           (numTrailingObjects(OverloadToken<ExplicitSpecifier>()) << 1);
+  }
+
 public:
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
   friend TrailingObjects;
 
   static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID,
-                                                bool InheritsConstructor);
+                                                uint64_t AllocKind);
   static CXXConstructorDecl *
   Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
          const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
-         bool isExplicit, bool isInline, bool isImplicitlyDeclared,
+         ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
          bool isConstexpr,
          InheritedConstructor Inherited = InheritedConstructor());
 
+  ExplicitSpecifier getExplicitSpecifier() {
+    return getExplicitSpecifierInternal();
+  }
+  const ExplicitSpecifier getExplicitSpecifier() const {
+    return getExplicitSpecifierInternal();
+  }
+
+  /// Return true if the declartion is already resolved to be explicit.
+  bool isExplicit() const { return getExplicitSpecifier().isExplicit(); }
+
   /// Iterates through the member/base initializer list.
   using init_iterator = CXXCtorInitializer **;
 
@@ -2603,11 +2699,6 @@ public:
     CtorInitializers = Initializers;
   }
 
-  /// Whether this function is explicit.
-  bool isExplicit() const {
-    return getCanonicalDecl()->isExplicitSpecified();
-  }
-
   /// Determine whether this constructor is a delegating constructor.
   bool isDelegatingConstructor() const {
     return (getNumCtorInitializers() == 1) &&
@@ -2786,34 +2877,39 @@ public:
 class CXXConversionDecl : public CXXMethodDecl {
   CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
                     const DeclarationNameInfo &NameInfo, QualType T,
-                    TypeSourceInfo *TInfo, bool isInline,
-                    bool isExplicitSpecified, bool isConstexpr,
-                    SourceLocation EndLocation)
+                    TypeSourceInfo *TInfo, bool isInline, ExplicitSpecifier ES,
+                    bool isConstexpr, SourceLocation EndLocation)
       : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
-                      SC_None, isInline, isConstexpr, EndLocation) {
-    setExplicitSpecified(isExplicitSpecified);
-  }
-
+                      SC_None, isInline, isConstexpr, EndLocation),
+        ExplicitSpec(ES) {}
   void anchor() override;
 
+  ExplicitSpecifier ExplicitSpec;
+
+  void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; }
+
 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, ExplicitSpecifier ES, bool isConstexpr,
+         SourceLocation EndLocation);
   static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
 
-  /// Whether this function is explicit.
-  bool isExplicit() const {
-    return getCanonicalDecl()->isExplicitSpecified();
+  ExplicitSpecifier getExplicitSpecifier() {
+    return getCanonicalDecl()->ExplicitSpec;
+  }
+
+  const ExplicitSpecifier getExplicitSpecifier() const {
+    return getCanonicalDecl()->ExplicitSpec;
   }
 
+  /// Return true if the declartion is already resolved to be explicit.
+  bool isExplicit() const { return getExplicitSpecifier().isExplicit(); }
+
   /// Returns the type that this conversion function is converting to.
   QualType getConversionType() const {
     return getType()->getAs<FunctionType>()->getReturnType();

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Wed May  8 20:59:21 2019
@@ -6171,6 +6171,9 @@ AST_MATCHER(CXXConstructorDecl, isDelega
 AST_POLYMORPHIC_MATCHER(isExplicit,
                         AST_POLYMORPHIC_SUPPORTED_TYPES(CXXConstructorDecl,
                                                         CXXConversionDecl)) {
+  // FIXME : it's not clear whether this should match a dependent
+  //         explicit(....). this matcher should also be able to match
+  //         CXXDeductionGuideDecl with explicit specifier.
   return Node.isExplicit();
 }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Wed May  8 20:59:21 2019
@@ -150,6 +150,8 @@ def ext_warn_duplicate_declspec : ExtWar
 def warn_duplicate_declspec : Warning<"%sub{duplicate_declspec}0">,
   InGroup<DuplicateDeclSpecifier>;
 
+def err_duplicate_declspec : Error<"%sub{duplicate_declspec}0">;
+
 def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">;
 
 def err_invalid_member_in_interface : Error<

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed May  8 20:59:21 2019
@@ -33,6 +33,10 @@ def err_asm_goto_not_supported_yet : Err
 
 let CategoryName = "Parse Issue" in {
 
+def warn_cxx2a_compat_explicit_bool : Warning<
+  "this expression will be parsed as explicit(bool) in C++2a">,
+  InGroup<CXX2aCompat>, DefaultIgnore;
+
 def ext_empty_translation_unit : Extension<
   "ISO C requires a translation unit to contain at least one declaration">,
   InGroup<DiagGroup<"empty-translation-unit">>;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed May  8 20:59:21 2019
@@ -83,11 +83,11 @@ def err_typecheck_converted_constant_exp
   "bind reference to a temporary">;
 def err_expr_not_cce : Error<
   "%select{case value|enumerator value|non-type template argument|"
-  "array size|constexpr if condition}0 "
+  "array size|constexpr if condition|explicit specifier argument}0 "
   "is not a constant expression">;
 def ext_cce_narrowing : ExtWarn<
   "%select{case value|enumerator value|non-type template argument|"
-  "array size|constexpr if condition}0 "
+  "array size|constexpr if condition|explicit specifier argument}0 "
   "%select{cannot be narrowed from type %2 to %3|"
   "evaluates to %2, which cannot be narrowed to type %3}1">,
   InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
@@ -2115,9 +2115,8 @@ def err_deduction_guide_wrong_scope : Er
   "deduction guide must be declared in the same scope as template %q0">;
 def err_deduction_guide_defines_function : Error<
   "deduction guide cannot have a function definition">;
-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_redeclared : Error<
+  "redeclaration of deduction guide">;
 def err_deduction_guide_specialized : Error<"deduction guide cannot be "
   "%select{explicitly instantiated|explicitly specialized}0">;
 def err_deduction_guide_template_not_deducible : Error<
@@ -3640,6 +3639,10 @@ def note_ovl_candidate : Note<
     "| has different qualifiers (expected %5 but found %6)"
     "| has different exception specification}4">;
 
+def note_ovl_candidate_explicit_forbidden : Note<
+    "candidate %0 ignored: cannot be explicit">;
+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<

Modified: cfe/trunk/include/clang/Basic/Specifiers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Specifiers.h (original)
+++ cfe/trunk/include/clang/Basic/Specifiers.h Wed May  8 20:59:21 2019
@@ -20,6 +20,14 @@
 #include "llvm/Support/ErrorHandling.h"
 
 namespace clang {
+
+  /// Define the meaning of possible values of the kind in ExplicitSpecifier.
+  enum class ExplicitSpecKind : unsigned {
+    ResolvedFalse,
+    ResolvedTrue,
+    Unresolved,
+  };
+
   /// Specifies the width of a type, e.g., short, long, or long long.
   enum TypeSpecifierWidth {
     TSW_unspecified,

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Wed May  8 20:59:21 2019
@@ -22,6 +22,7 @@
 #ifndef LLVM_CLANG_SEMA_DECLSPEC_H
 #define LLVM_CLANG_SEMA_DECLSPEC_H
 
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/Basic/ExceptionSpecificationType.h"
 #include "clang/Basic/Lambda.h"
@@ -356,7 +357,6 @@ private:
   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 +371,9 @@ private:
     Expr *ExprRep;
   };
 
+  /// ExplicitSpecifier - Store information about explicit spicifer.
+  ExplicitSpecifier FS_explicit_specifier;
+
   // attributes.
   ParsedAttributes Attrs;
 
@@ -393,6 +396,7 @@ private:
   SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc,
       TQ_unalignedLoc;
   SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
+  SourceLocation FS_explicitCloseParenLoc;
   SourceLocation FS_forceinlineLoc;
   SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
   SourceLocation TQ_pipeLoc;
@@ -420,31 +424,18 @@ public:
   }
 
   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(), Attrs(attrFactory), writtenBS(),
+        ObjCQualifiers(nullptr) {}
 
   // storage-class-specifier
   SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
@@ -570,11 +561,22 @@ public:
     return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc;
   }
 
+  ExplicitSpecifier 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.isSpecified();
+  }
   SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; }
+  SourceRange getExplicitSpecRange() const {
+    return FS_explicit_specifier.getExpr()
+               ? SourceRange(FS_explicitLoc, FS_explicitCloseParenLoc)
+               : SourceRange(FS_explicitLoc);
+  }
 
   bool isNoreturnSpecified() const { return FS_noreturn_specified; }
   SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
@@ -586,8 +588,9 @@ public:
     FS_forceinlineLoc = SourceLocation();
     FS_virtual_specified = false;
     FS_virtualLoc = SourceLocation();
-    FS_explicit_specified = false;
+    FS_explicit_specifier = ExplicitSpecifier();
     FS_explicitLoc = SourceLocation();
+    FS_explicitCloseParenLoc = SourceLocation();
     FS_noreturn_specified = false;
     FS_noreturnLoc = SourceLocation();
   }
@@ -706,7 +709,8 @@ public:
   bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
                               unsigned &DiagID);
   bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
-                               unsigned &DiagID);
+                               unsigned &DiagID, ExplicitSpecifier ExplicitSpec,
+                               SourceLocation CloseParenLoc);
   bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
                                unsigned &DiagID);
 

Modified: cfe/trunk/include/clang/Sema/Overload.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Overload.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Overload.h (original)
+++ cfe/trunk/include/clang/Sema/Overload.h Wed May  8 20:59:21 2019
@@ -705,6 +705,11 @@ class Sema;
     /// attribute disabled it.
     ovl_fail_enable_if,
 
+    /// This candidate constructor or conversion fonction
+    /// is used implicitly but the explicit(bool) specifier
+    /// 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,
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Wed May  8 20:59:21 2019
@@ -2743,7 +2743,8 @@ public:
     CCEK_Enumerator,  ///< Enumerator value with fixed underlying type.
     CCEK_TemplateArg, ///< Value of a non-type template parameter.
     CCEK_NewExpr,     ///< Constant expression in a noptr-new-declarator.
-    CCEK_ConstexprIf  ///< Condition in a constexpr if statement.
+    CCEK_ConstexprIf, ///< Condition in a constexpr if statement.
+    CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier.
   };
   ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
                                               llvm::APSInt &Value, CCEKind CCE);
@@ -2865,7 +2866,8 @@ public:
                             OverloadCandidateSet &CandidateSet,
                             bool SuppressUserConversions = false,
                             bool PartialOverloading = false,
-                            bool AllowExplicit = false,
+                            bool AllowExplicit = true,
+                            bool AllowExplicitConversion = false,
                             ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
                             ConversionSequenceList EarlyConversions = None);
   void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
@@ -2904,7 +2906,7 @@ public:
       FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
       TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
       OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
-      bool PartialOverloading = false,
+      bool PartialOverloading = false, bool AllowExplicit = true,
       ADLCallKind IsADLCandidate = ADLCallKind::NotADL);
   bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
                                     ArrayRef<QualType> ParamTypes,
@@ -2916,20 +2918,16 @@ public:
                                     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,
@@ -10158,6 +10156,14 @@ public:
   ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E,
                                    bool IsConstexpr = false);
 
+  /// ActOnExplicitBoolSpecifier - Build an ExplicitSpecifier from an expression
+  /// found in an explicit(bool) specifier.
+  ExplicitSpecifier ActOnExplicitBoolSpecifier(Expr *E);
+
+  /// tryResolveExplicitSpecifier - Attempt to resolve the explict specifier.
+  /// Returns true if the explicit specifier is now resolved.
+  bool tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec);
+
   /// DiagnoseAssignmentAsCondition - Given that an expression is
   /// being used as a boolean condition, warn if it's an assignment.
   void DiagnoseAssignmentAsCondition(Expr *E);

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Wed May  8 20:59:21 2019
@@ -1441,9 +1441,6 @@ namespace serialization {
       /// A CXXConstructorDecl record.
       DECL_CXX_CONSTRUCTOR,
 
-      /// A CXXConstructorDecl record for an inherited constructor.
-      DECL_CXX_INHERITED_CONSTRUCTOR,
-
       /// A CXXDestructorDecl record.
       DECL_CXX_DESTRUCTOR,
 

Modified: cfe/trunk/include/clang/Serialization/ASTReader.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTReader.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTReader.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTReader.h Wed May  8 20:59:21 2019
@@ -2430,6 +2430,14 @@ public:
                                                  ID);
   }
 
+  ExplicitSpecifier readExplicitSpec() {
+    uint64_t Kind = readInt();
+    bool HasExpr = Kind & 0x1;
+    Kind = Kind >> 1;
+    return ExplicitSpecifier(HasExpr ? readExpr() : nullptr,
+                             static_cast<ExplicitSpecKind>(Kind));
+  }
+
   void readExceptionSpec(SmallVectorImpl<QualType> &ExceptionStorage,
                          FunctionProtoType::ExceptionSpecInfo &ESI) {
     return Reader->readExceptionSpec(*F, ExceptionStorage, ESI, Record, Idx);

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Wed May  8 20:59:21 2019
@@ -3076,11 +3076,20 @@ ExpectedDecl ASTNodeImporter::VisitFunct
   // Create the imported function.
   FunctionDecl *ToFunction = nullptr;
   if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
+    Expr *ExplicitExpr = nullptr;
+    if (FromConstructor->getExplicitSpecifier().getExpr()) {
+      auto Imp = importSeq(FromConstructor->getExplicitSpecifier().getExpr());
+      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,
+            ExplicitSpecifier(
+                ExplicitExpr,
+                FromConstructor->getExplicitSpecifier().getKind()),
+            D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
       return ToFunction;
   } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
 
@@ -3106,10 +3115,19 @@ ExpectedDecl ASTNodeImporter::VisitFunct
     ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg);
   } else if (CXXConversionDecl *FromConversion =
                  dyn_cast<CXXConversionDecl>(D)) {
+    Expr *ExplicitExpr = nullptr;
+    if (FromConversion->getExplicitSpecifier().getExpr()) {
+      auto Imp = importSeq(FromConversion->getExplicitSpecifier().getExpr());
+      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()))
+            ExplicitSpecifier(ExplicitExpr,
+                              FromConversion->getExplicitSpecifier().getKind()),
+            D->isConstexpr(), SourceLocation()))
       return ToFunction;
   } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
     if (GetImportedOrCreateDecl<CXXMethodDecl>(

Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original)
+++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Wed May  8 20:59:21 2019
@@ -982,13 +982,15 @@ static bool IsStructurallyEquivalent(Str
 
   if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
     auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
-    if (Constructor1->isExplicit() != Constructor2->isExplicit())
+    if (!Constructor1->getExplicitSpecifier().isEquivalent(
+            Constructor2->getExplicitSpecifier()))
       return false;
   }
 
   if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
     auto *Conversion2 = cast<CXXConversionDecl>(Method2);
-    if (Conversion1->isExplicit() != Conversion2->isExplicit())
+    if (!Conversion1->getExplicitSpecifier().isEquivalent(
+            Conversion2->getExplicitSpecifier()))
       return false;
     if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
                                   Conversion2->getConversionType()))

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed May  8 20:59:21 2019
@@ -2713,7 +2713,6 @@ FunctionDecl::FunctionDecl(Kind DK, ASTC
   FunctionDeclBits.SClass = S;
   FunctionDeclBits.IsInline = isInlineSpecified;
   FunctionDeclBits.IsInlineSpecified = isInlineSpecified;
-  FunctionDeclBits.IsExplicitSpecified = false;
   FunctionDeclBits.IsVirtualAsWritten = false;
   FunctionDeclBits.IsPure = false;
   FunctionDeclBits.HasInheritedPrototype = false;

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed May  8 20:59:21 2019
@@ -1879,19 +1879,47 @@ bool CXXRecordDecl::mayBeAbstract() cons
 
 void CXXDeductionGuideDecl::anchor() {}
 
+bool ExplicitSpecifier::isEquivalent(const ExplicitSpecifier Other) const {
+  if ((getKind() != Other.getKind() ||
+       getKind() == ExplicitSpecKind::Unresolved)) {
+    if (getKind() == ExplicitSpecKind::Unresolved &&
+        Other.getKind() == ExplicitSpecKind::Unresolved) {
+      ODRHash SelfHash, OtherHash;
+      SelfHash.AddStmt(getExpr());
+      OtherHash.AddStmt(Other.getExpr());
+      return SelfHash.CalculateHash() == OtherHash.CalculateHash();
+    } else
+      return false;
+  }
+  return true;
+}
+
+ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) {
+  switch (Function->getDeclKind()) {
+  case Decl::Kind::CXXConstructor:
+    return cast<CXXConstructorDecl>(Function)->getExplicitSpecifier();
+  case Decl::Kind::CXXConversion:
+    return cast<CXXConversionDecl>(Function)->getExplicitSpecifier();
+  case Decl::Kind::CXXDeductionGuide:
+    return cast<CXXDeductionGuideDecl>(Function)->getExplicitSpecifier();
+  default:
+    return {};
+  }
+}
+
 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,
+    ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
+    TypeSourceInfo *TInfo, SourceLocation EndLocation) {
+  return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, 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(), ExplicitSpecifier(), DeclarationNameInfo(),
+      QualType(), nullptr, SourceLocation());
 }
 
 void CXXMethodDecl::anchor() {}
@@ -2329,47 +2357,54 @@ SourceRange CXXCtorInitializer::getSourc
 CXXConstructorDecl::CXXConstructorDecl(
     ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
     const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
-    bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared,
+    ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
     bool isConstexpr, InheritedConstructor Inherited)
     : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
                     SC_None, isInline, isConstexpr, SourceLocation()) {
   setNumCtorInitializers(0);
   setInheritingConstructor(static_cast<bool>(Inherited));
   setImplicit(isImplicitlyDeclared);
+  CXXConstructorDeclBits.HasTrailingExplicitSpecifier = ES.getExpr() ? 1 : 0;
   if (Inherited)
     *getTrailingObjects<InheritedConstructor>() = Inherited;
-  setExplicitSpecified(isExplicitSpecified);
+  setExplicitSpecifier(ES);
 }
 
 void CXXConstructorDecl::anchor() {}
 
 CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
                                                            unsigned ID,
-                                                           bool Inherited) {
-  unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited);
+                                                           uint64_t AllocKind) {
+  bool hasTraillingExplicit = static_cast<bool>(AllocKind & TAKHasTailExplicit);
+  bool isInheritingConstructor =
+      static_cast<bool>(AllocKind & TAKInheritsConstructor);
+  unsigned Extra =
+      additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
+          isInheritingConstructor, hasTraillingExplicit);
   auto *Result = new (C, ID, Extra) CXXConstructorDecl(
       C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
-      false, false, false, false, InheritedConstructor());
-  Result->setInheritingConstructor(Inherited);
+      ExplicitSpecifier(), false, false, false, InheritedConstructor());
+  Result->setInheritingConstructor(isInheritingConstructor);
+  Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
+      hasTraillingExplicit;
+  Result->setExplicitSpecifier(ExplicitSpecifier());
   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,
+    ExplicitSpecifier ES, 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);
+      additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
+          Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
+  return new (C, RD, Extra)
+      CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
+                         isImplicitlyDeclared, isConstexpr, Inherited);
 }
 
 CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
@@ -2520,25 +2555,21 @@ 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, ExplicitSpecifier(), 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, ExplicitSpecifier ES, 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, ES, isConstexpr, EndLocation);
 }
 
 bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Wed May  8 20:59:21 2019
@@ -566,6 +566,21 @@ void DeclPrinter::VisitEnumConstantDecl(
   }
 }
 
+static void printExplicitSpecifier(ExplicitSpecifier ES, llvm::raw_ostream &Out,
+                                   PrintingPolicy &Policy,
+                                   unsigned Indentation) {
+  std::string Proto = "explicit";
+  llvm::raw_string_ostream EOut(Proto);
+  if (ES.getExpr()) {
+    EOut << "(";
+    ES.getExpr()->printPretty(EOut, nullptr, Policy, Indentation);
+    EOut << ")";
+  }
+  EOut << " ";
+  EOut.flush();
+  Out << EOut.str();
+}
+
 void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
   if (!D->getDescribedFunctionTemplate() &&
       !D->isFunctionTemplateSpecialization())
@@ -596,10 +611,9 @@ void DeclPrinter::VisitFunctionDecl(Func
     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 ";
+    ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
+    if (ExplicitSpec.isSpecified())
+      printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation);
   }
 
   PrintingPolicy SubPolicy(Policy);

Modified: cfe/trunk/lib/Frontend/InitPreprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/InitPreprocessor.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/InitPreprocessor.cpp (original)
+++ cfe/trunk/lib/Frontend/InitPreprocessor.cpp Wed May  8 20:59:21 2019
@@ -540,6 +540,8 @@ static void InitializeCPlusPlusFeatureTe
     Builder.defineMacro("__cpp_template_template_args", "201611L");
 
   // C++20 features.
+  if (LangOpts.CPlusPlus2a)
+    Builder.defineMacro("__cpp_conditional_explicit", "201806L");
   if (LangOpts.Char8)
     Builder.defineMacro("__cpp_char8_t", "201811L");
   Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Wed May  8 20:59:21 2019
@@ -2480,12 +2480,12 @@ void Parser::ParseSpecifierQualifierList
       Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
     if (DS.isVirtualSpecified())
       Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
-    if (DS.isExplicitSpecified())
+    if (DS.hasExplicitSpecifier())
       Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
     DS.ClearFunctionSpecs();
   }
 
-  // Issue diagnostic and remove constexpr specfier if present.
+  // Issue diagnostic and remove constexpr specifier if present.
   if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) {
     Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
     DS.ClearConstexprSpec();
@@ -3004,9 +3004,13 @@ void Parser::ParseDeclarationSpecifiers(
   while (1) {
     bool isInvalid = false;
     bool isStorageClass = false;
+    bool isAlreadyConsumed = false;
     const char *PrevSpec = nullptr;
     unsigned DiagID = 0;
 
+    // This value need to be set when isAlreadyConsumed is set to true.
+    SourceLocation RangeEnd;
+
     // HACK: MSVC doesn't consider _Atomic to be a keyword and its STL
     // implementation for VS2013 uses _Atomic as an identifier for one of the
     // classes in <atomic>.
@@ -3558,9 +3562,34 @@ void Parser::ParseDeclarationSpecifiers(
         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 CloseParenLoc;
+      ExplicitSpecifier ExplicitSpec(nullptr, ExplicitSpecKind::ResolvedTrue);
+      isAlreadyConsumed = true;
+      RangeEnd = ExplicitLoc;
+      ConsumeToken(); // kw_explicit
+      if (Tok.is(tok::l_paren)) {
+        if (getLangOpts().CPlusPlus2a) {
+          ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
+          BalancedDelimiterTracker Tracker(*this, tok::l_paren);
+          Tracker.consumeOpen();
+          ExplicitExpr = ParseConstantExpression();
+          RangeEnd = Tok.getLocation();
+          if (ExplicitExpr.isUsable()) {
+            CloseParenLoc = Tok.getLocation();
+            Tracker.consumeClose();
+            ExplicitSpec =
+                Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
+          } else
+            Tracker.skipToEnd();
+        } else
+          Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
+      }
+      isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
+                                             ExplicitSpec, CloseParenLoc);
       break;
+    }
     case tok::kw__Noreturn:
       if (!getLangOpts().C11)
         Diag(Loc, diag::ext_c11_noreturn);
@@ -3904,25 +3933,32 @@ void Parser::ParseDeclarationSpecifiers(
       // If a type specifier follows, it will be diagnosed elsewhere.
       continue;
     }
+
+    assert(!isAlreadyConsumed || RangeEnd != SourceLocation() &&
+                                     "both or neither of isAlreadyConsumed and "
+                                     "RangeEnd needs to be set");
+    DS.SetRangeEnd(isAlreadyConsumed ? RangeEnd : Tok.getLocation());
+
     // If the specifier wasn't legal, issue a diagnostic.
     if (isInvalid) {
       assert(PrevSpec && "Method did not return previous specifier!");
       assert(DiagID);
 
       if (DiagID == diag::ext_duplicate_declspec ||
-          DiagID == diag::ext_warn_duplicate_declspec)
-        Diag(Tok, DiagID)
-          << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
+          DiagID == diag::ext_warn_duplicate_declspec ||
+          DiagID == diag::err_duplicate_declspec)
+        Diag(Loc, DiagID) << PrevSpec
+                          << FixItHint::CreateRemoval(
+                                 SourceRange(Loc, DS.getEndLoc()));
       else if (DiagID == diag::err_opencl_unknown_type_specifier) {
-        Diag(Tok, DiagID) << getLangOpts().OpenCLCPlusPlus
-            << getLangOpts().getOpenCLVersionTuple().getAsString()
-            << PrevSpec << isStorageClass;
+        Diag(Loc, DiagID) << getLangOpts().OpenCLCPlusPlus
+                          << getLangOpts().getOpenCLVersionTuple().getAsString()
+                          << PrevSpec << isStorageClass;
       } else
-        Diag(Tok, DiagID) << PrevSpec;
+        Diag(Loc, DiagID) << PrevSpec;
     }
 
-    DS.SetRangeEnd(Tok.getLocation());
-    if (DiagID != diag::err_bool_redeclaration)
+    if (DiagID != diag::err_bool_redeclaration && !isAlreadyConsumed)
       // After an error the next token can be an annotation token.
       ConsumeAnyToken();
 

Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Wed May  8 20:59:21 2019
@@ -445,7 +445,7 @@ unsigned DeclSpec::getParsedSpecifiers()
   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;
@@ -959,17 +959,24 @@ bool DeclSpec::setFunctionSpecVirtual(So
 }
 
 bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc,
-                                       const char *&PrevSpec,
-                                       unsigned &DiagID) {
+                                       const char *&PrevSpec, unsigned &DiagID,
+                                       ExplicitSpecifier ExplicitSpec,
+                                       SourceLocation CloseParenLoc) {
+  assert((ExplicitSpec.getKind() == ExplicitSpecKind::ResolvedTrue ||
+          ExplicitSpec.getExpr()) &&
+         "invalid ExplicitSpecifier");
   // 'explicit explicit' is ok, but warn as this is likely not what the user
   // intended.
-  if (FS_explicit_specified) {
-    DiagID = diag::warn_duplicate_declspec;
+  if (hasExplicitSpecifier()) {
+    DiagID = (ExplicitSpec.getExpr() || FS_explicit_specifier.getExpr())
+                 ? diag::err_duplicate_declspec
+                 : diag::ext_warn_duplicate_declspec;
     PrevSpec = "explicit";
     return true;
   }
-  FS_explicit_specified = true;
+  FS_explicit_specifier = ExplicitSpec;
   FS_explicitLoc = Loc;
+  FS_explicitCloseParenLoc = CloseParenLoc;
   return false;
 }
 
@@ -1311,23 +1318,26 @@ void DeclSpec::Finish(Sema &S, const Pri
   //   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;
+    FixItHint Hint;
     SourceLocation SCLoc;
 
     if (isVirtualSpecified()) {
       Keyword = "virtual";
       SCLoc = getVirtualSpecLoc();
+      Hint = FixItHint::CreateRemoval(SCLoc);
     } else {
       Keyword = "explicit";
       SCLoc = getExplicitSpecLoc();
+      Hint = FixItHint::CreateRemoval(getExplicitSpecRange());
     }
 
-    FixItHint Hint = FixItHint::CreateRemoval(SCLoc);
     S.Diag(SCLoc, diag::err_friend_decl_spec)
       << Keyword << Hint;
 
-    FS_virtual_specified = FS_explicit_specified = false;
+    FS_virtual_specified = false;
+    FS_explicit_specifier = ExplicitSpecifier();
     FS_virtualLoc = FS_explicitLoc = SourceLocation();
   }
 

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Wed May  8 20:59:21 2019
@@ -4970,7 +4970,8 @@ QualType Sema::ProduceConstructorSignatu
       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()),

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed May  8 20:59:21 2019
@@ -5725,7 +5725,7 @@ void Sema::DiagnoseFunctionSpecifiers(co
     Diag(DS.getVirtualSpecLoc(),
          diag::err_virtual_non_function);
 
-  if (DS.isExplicitSpecified())
+  if (DS.hasExplicitSpecifier())
     Diag(DS.getExplicitSpecLoc(),
          diag::err_explicit_non_function);
 
@@ -7989,7 +7989,7 @@ static FunctionDecl* CreateNewFunctionDe
     return NewFD;
   }
 
-  bool isExplicit = D.getDeclSpec().isExplicitSpecified();
+  ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
   bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
 
   // Check that the return type is not an abstract class type.
@@ -8009,7 +8009,7 @@ static FunctionDecl* CreateNewFunctionDe
     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) {
@@ -8054,13 +8054,13 @@ static FunctionDecl* CreateNewFunctionDe
     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,
@@ -8421,7 +8421,7 @@ Sema::ActOnFunctionDeclarator(Scope *S,
   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()) {
@@ -8604,20 +8604,20 @@ Sema::ActOnFunctionDeclarator(Scope *S,
     //  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() &&
+    if (hasExplicit && !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());
+            << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
       } 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());
+            << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
       }
     }
 

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed May  8 20:59:21 2019
@@ -657,14 +657,13 @@ bool Sema::MergeCXXFunctionDecl(Function
     Invalid = true;
   }
 
-  // FIXME: It's not clear what should happen if multiple declarations of a
-  // 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()) {
-    Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
-      << NewGuide->isExplicitSpecified();
+  // C++17 [temp.deduct.guide]p3:
+  //   Two deduction guide declarations in the same translation unit
+  //   for the same class template shall not have equivalent
+  //   parameter-declaration-clauses.
+  if (isa<CXXDeductionGuideDecl>(New) &&
+      !New->isFunctionTemplateSpecialization()) {
+    Diag(New->getLocation(), diag::err_deduction_guide_redeclared);
     Diag(Old->getLocation(), diag::note_previous_declaration);
   }
 
@@ -8594,12 +8593,12 @@ void Sema::CheckConversionDeclarator(Dec
     R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
 
   // C++0x explicit conversion operators.
-  if (DS.isExplicitSpecified())
+  if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus2a)
     Diag(DS.getExplicitSpecLoc(),
          getLangOpts().CPlusPlus11
              ? diag::warn_cxx98_compat_explicit_conversion_functions
              : diag::ext_explicit_conversion_functions)
-        << SourceRange(DS.getExplicitSpecLoc());
+        << SourceRange(DS.getExplicitSpecRange());
 }
 
 /// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
@@ -10822,6 +10821,28 @@ struct ComputingExceptionSpec {
 };
 }
 
+bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) {
+  llvm::APSInt Result;
+  ExprResult Converted = CheckConvertedConstantExpression(
+      ExplicitSpec.getExpr(), Context.BoolTy, Result, CCEK_ExplicitBool);
+  ExplicitSpec.setExpr(Converted.get());
+  if (Converted.isUsable() && !Converted.get()->isValueDependent()) {
+    ExplicitSpec.setKind(Result.getBoolValue()
+                             ? ExplicitSpecKind::ResolvedTrue
+                             : ExplicitSpecKind::ResolvedFalse);
+    return true;
+  }
+  ExplicitSpec.setKind(ExplicitSpecKind::Unresolved);
+  return false;
+}
+
+ExplicitSpecifier Sema::ActOnExplicitBoolSpecifier(Expr *ExplicitExpr) {
+  ExplicitSpecifier ES(ExplicitExpr, ExplicitSpecKind::Unresolved);
+  if (!ExplicitExpr->isTypeDependent())
+    tryResolveExplicitSpecifier(ES);
+  return ES;
+}
+
 static Sema::ImplicitExceptionSpecification
 ComputeDefaultedSpecialMemberExceptionSpec(
     Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
@@ -10970,9 +10991,9 @@ CXXConstructorDecl *Sema::DeclareImplici
     = 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, ExplicitSpecifier(),
+      /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr);
   DefaultCon->setAccess(AS_public);
   DefaultCon->setDefaulted();
 
@@ -11091,7 +11112,7 @@ Sema::findInheritingConstructor(SourceLo
 
   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())
@@ -12543,8 +12564,9 @@ CXXConstructorDecl *Sema::DeclareImplici
   //   member of its class.
   CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
       Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
-      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
-      Constexpr);
+      ExplicitSpecifier(),
+      /*isInline=*/true,
+      /*isImplicitlyDeclared=*/true, Constexpr);
   CopyConstructor->setAccess(AS_public);
   CopyConstructor->setDefaulted();
 
@@ -12673,8 +12695,9 @@ CXXConstructorDecl *Sema::DeclareImplici
   //   member of its class.
   CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
       Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
-      /*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
-      Constexpr);
+      ExplicitSpecifier(),
+      /*isInline=*/true,
+      /*isImplicitlyDeclared=*/true, Constexpr);
   MoveConstructor->setAccess(AS_public);
   MoveConstructor->setDefaulted();
 

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Wed May  8 20:59:21 2019
@@ -3763,9 +3763,10 @@ ResolveConstructorOverload(Sema &S, Sour
          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 +3780,8 @@ ResolveConstructorOverload(Sema &S, Sour
                                hasCopyOrMoveCtorParam(S.Context, Info);
       S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
                              CandidateSet, SuppressUserConversions,
-                             /*PartialOverloading=*/false,
-                             /*AllowExplicit=*/AllowExplicitConv);
+                             /*PartialOverloading=*/false, AllowExplicit,
+                             AllowExplicitConv);
     }
   }
 
@@ -3813,16 +3814,17 @@ ResolveConstructorOverload(Sema &S, Sour
         else
           Conv = cast<CXXConversionDecl>(D);
 
-        if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
+        if (AllowExplicit || !Conv->isExplicit()) {
           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 +4370,16 @@ static OverloadingResult TryRefInitWithC
       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);
       }
     }
   }
@@ -4410,17 +4414,17 @@ static OverloadingResult TryRefInitWithC
       // candidates with reference-compatible results? That might be needed to
       // break recursion.
       if ((AllowExplicitConvs || !Conv->isExplicit()) &&
-          (AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
+          (AllowRValues ||
+           Conv->getConversionType()->isLValueReferenceType())) {
         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);
       }
     }
   }
@@ -4996,14 +5000,16 @@ static void TryUserDefinedConversion(Sem
         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);
         }
       }
     }
@@ -5038,12 +5044,12 @@ static void TryUserDefinedConversion(Sem
 
         if (AllowExplicit || !Conv->isExplicit()) {
           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);
         }
       }
@@ -9336,6 +9342,7 @@ QualType Sema::DeduceTemplateSpecializat
   OverloadCandidateSet::iterator Best;
 
   bool HasAnyDeductionGuide = false;
+  bool AllowExplicit = !Kind.isCopyInit() || ListInit;
 
   auto tryToResolveOverload =
       [&](bool OnlyListConstructors) -> OverloadingResult {
@@ -9361,7 +9368,7 @@ QualType Sema::DeduceTemplateSpecializat
       //   converting constructors (12.3.1) of that class.
       // C++ [over.match.copy]p1: (non-list copy-initialization from class)
       //   The converting constructors of T are candidate functions.
-      if (Kind.isCopyInit() && !ListInit) {
+      if (!AllowExplicit) {
         // Only consider converting constructors.
         if (GD->isExplicit())
           continue;
@@ -9396,11 +9403,13 @@ QualType Sema::DeduceTemplateSpecializat
 
       if (TD)
         AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
-                                     Inits, Candidates,
-                                     SuppressUserConversions);
+                                     Inits, Candidates, SuppressUserConversions,
+                                     /*PartialOverloading*/ false,
+                                     AllowExplicit);
       else
         AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
-                             SuppressUserConversions);
+                             SuppressUserConversions,
+                             /*PartialOverloading*/ false, AllowExplicit);
     }
     return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
   };

Modified: cfe/trunk/lib/Sema/SemaLambda.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLambda.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLambda.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLambda.cpp Wed May  8 20:59:21 2019
@@ -1325,7 +1325,7 @@ static void addFunctionPointerConversion
   CXXConversionDecl *Conversion = CXXConversionDecl::Create(
       S.Context, Class, Loc,
       DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
-      /*isInline=*/true, /*isExplicit=*/false,
+      /*isInline=*/true, ExplicitSpecifier(),
       /*isConstexpr=*/S.getLangOpts().CPlusPlus17,
       CallOperator->getBody()->getEndLoc());
   Conversion->setAccess(AS_public);
@@ -1412,7 +1412,7 @@ static void addBlockPointerConversion(Se
   CXXConversionDecl *Conversion = CXXConversionDecl::Create(
       S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
       S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
-      /*isInline=*/true, /*isExplicit=*/false,
+      /*isInline=*/true, ExplicitSpecifier(),
       /*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
   Conversion->setAccess(AS_public);
   Conversion->setImplicit(true);

Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed May  8 20:59:21 2019
@@ -3041,10 +3041,11 @@ Sema::SpecialMemberOverloadResult Sema::
                            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);
       else
         AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
-                             true);
+                             /*SuppressUserConversions*/ true);
     } else if (FunctionTemplateDecl *Tmpl =
                  dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
       if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Wed May  8 20:59:21 2019
@@ -3242,10 +3242,13 @@ IsInitializerListConstructorConversion(S
       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);
     }
   }
 
@@ -3372,13 +3375,15 @@ IsUserDefinedConversion(Sema &S, Expr *F
             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);
         }
       }
     }
@@ -3410,14 +3415,13 @@ IsUserDefinedConversion(Sema &S, Expr *F
 
         if (AllowExplicit || !Conv->isExplicit()) {
           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);
         }
       }
     }
@@ -4445,13 +4449,13 @@ FindConversionForRefInit(Sema &S, Implic
     }
 
     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);
@@ -5414,7 +5418,7 @@ static ExprResult CheckConvertedConstant
   //  condition shall be a contextually converted constant expression of type
   //  bool.
   ImplicitConversionSequence ICS =
-      CCE == Sema::CCEK_ConstexprIf
+      CCE == Sema::CCEK_ConstexprIf || CCE == Sema::CCEK_ExplicitBool
           ? TryContextuallyConvertToBool(S, From)
           : TryCopyInitialization(S, From, T,
                                   /*SuppressUserConversions=*/false,
@@ -5730,12 +5734,13 @@ collectViableConversionCandidates(Sema &
 
     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);
   }
 }
 
@@ -5987,13 +5992,11 @@ static bool IsAcceptableNonMemberOperato
 /// \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");
@@ -6150,13 +6153,11 @@ void Sema::AddOverloadCandidate(Function
       // (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;
@@ -6170,6 +6171,15 @@ void Sema::AddOverloadCandidate(Function
     }
   }
 
+  if (!AllowExplicit) {
+    ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function);
+    if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) {
+      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;
@@ -6759,7 +6769,7 @@ void Sema::AddTemplateOverloadCandidate(
     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;
 
@@ -6808,9 +6818,10 @@ void Sema::AddTemplateOverloadCandidate(
   // 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
@@ -6915,14 +6926,11 @@ static bool isAllowableExplicitConversio
 /// 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();
@@ -7081,6 +7089,13 @@ Sema::AddConversionCandidate(CXXConversi
            "Can only end up with a standard conversion sequence or failure");
   }
 
+  if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() !=
+                            ExplicitSpecKind::ResolvedFalse) {
+    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;
@@ -7100,14 +7115,11 @@ Sema::AddConversionCandidate(CXXConversi
 /// 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");
 
@@ -7137,7 +7149,7 @@ Sema::AddTemplateConversionCandidate(Fun
   assert(Specialization && "Missing function template specialization?");
   AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
                          CandidateSet, AllowObjCConversionOnExplicit,
-                         AllowResultConversion);
+                         AllowExplicit, AllowResultConversion);
 }
 
 /// AddSurrogateCandidate - Adds a "surrogate" candidate function that
@@ -8991,12 +9003,14 @@ Sema::AddArgumentDependentLookupCandidat
 
       AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
                            /*SupressUserConversions=*/false, PartialOverloading,
-                           /*AllowExplicit=*/false, ADLCallKind::UsesADL);
+                           /*AllowExplicitConversions*/ false,
+                           /*AllowExplicit*/ true, ADLCallKind::UsesADL);
     } else {
-      AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl,
-                                   ExplicitTemplateArgs, Args, CandidateSet,
-                                   /*SupressUserConversions=*/false,
-                                   PartialOverloading, ADLCallKind::UsesADL);
+      AddTemplateOverloadCandidate(
+          cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
+          CandidateSet,
+          /*SuppressUserConversions=*/false, PartialOverloading,
+          /*AllowExplicit*/true, ADLCallKind::UsesADL);
     }
   }
 }
@@ -10327,6 +10341,33 @@ static void DiagnoseFailedEnableIfAttr(S
       << Attr->getCond()->getSourceRange() << Attr->getMessage();
 }
 
+static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
+  ExplicitSpecifier ES;
+  const char *DeclName;
+  switch (Cand->Function->getDeclKind()) {
+  case Decl::Kind::CXXConstructor:
+    ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier();
+    DeclName = "constructor";
+    break;
+  case Decl::Kind::CXXConversion:
+    ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier();
+    DeclName = "conversion operator";
+    break;
+  case Decl::Kind::CXXDeductionGuide:
+    ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier();
+    DeclName = "deductiong guide";
+    break;
+  default:
+    llvm_unreachable("invalid Decl");
+  }
+  assert(ES.getExpr() && "null expression should be handled before");
+  S.Diag(Cand->Function->getLocation(),
+         diag::note_ovl_candidate_explicit_forbidden)
+      << DeclName;
+  S.Diag(ES.getExpr()->getBeginLoc(),
+         diag::note_explicit_bool_resolved_to_true);
+}
+
 static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
   FunctionDecl *Callee = Cand->Function;
 
@@ -10411,6 +10452,9 @@ static void NoteFunctionCandidate(Sema &
   case ovl_fail_enable_if:
     return DiagnoseFailedEnableIfAttr(S, Cand);
 
+  case ovl_fail_explicit_resolved:
+    return DiagnoseFailedExplicitSpec(S, Cand);
+
   case ovl_fail_ext_disabled:
     return DiagnoseOpenCLExtensionDisabled(S, Cand);
 
@@ -12981,8 +13025,9 @@ Sema::BuildCallToMemberFunction(Scope *S
 
       // 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);
       } else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
         // If explicit template arguments were provided, we can't call a
         // non-template member function.

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed May  8 20:59:21 2019
@@ -1156,7 +1156,7 @@ NamedDecl *Sema::ActOnNonTypeTemplatePar
     if (DS.isVirtualSpecified())
       EmitDiag(DS.getVirtualSpecLoc());
 
-    if (DS.isExplicitSpecified())
+    if (DS.hasExplicitSpecifier())
       EmitDiag(DS.getExplicitSpecLoc());
 
     if (DS.isNoreturnSpecified())
@@ -1836,8 +1836,8 @@ struct ConvertConstructorToDeductionGuid
       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());
   }
 
@@ -1866,8 +1866,8 @@ struct ConvertConstructorToDeductionGuid
       Params.push_back(NewParam);
     }
 
-    return buildDeductionGuide(Template->getTemplateParameters(), false, TSI,
-                               Loc, Loc, Loc);
+    return buildDeductionGuide(Template->getTemplateParameters(),
+                               ExplicitSpecifier(), TSI, Loc, Loc, Loc);
   }
 
 private:
@@ -2017,7 +2017,7 @@ private:
   }
 
   NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
-                                 bool Explicit, TypeSourceInfo *TInfo,
+                                 ExplicitSpecifier ES, TypeSourceInfo *TInfo,
                                  SourceLocation LocStart, SourceLocation Loc,
                                  SourceLocation LocEnd) {
     DeclarationNameInfo Name(DeductionGuideName, Loc);
@@ -2026,8 +2026,8 @@ private:
 
     // 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, ES, Name,
+                                      TInfo->getType(), TInfo, LocEnd);
     Guide->setImplicit();
     Guide->setParams(Params);
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed May  8 20:59:21 2019
@@ -366,6 +366,29 @@ static void instantiateDependentAMDGPUFl
                                    Attr.getSpellingListIndex());
 }
 
+static ExplicitSpecifier
+instantiateExplicitSpecifier(Sema &S,
+                             const MultiLevelTemplateArgumentList &TemplateArgs,
+                             ExplicitSpecifier ES, FunctionDecl *New) {
+  if (!ES.getExpr())
+    return ES;
+  Expr *OldCond = ES.getExpr();
+  Expr *Cond = nullptr;
+  {
+    EnterExpressionEvaluationContext Unevaluated(
+        S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+    ExprResult SubstResult = S.SubstExpr(OldCond, TemplateArgs);
+    if (SubstResult.isInvalid()) {
+      return ExplicitSpecifier::Invalid();
+    }
+    Cond = SubstResult.get();
+  }
+  ExplicitSpecifier Result(Cond, ES.getKind());
+  if (!Cond->isTypeDependent())
+    S.tryResolveExplicitSpecifier(Result);
+  return Result;
+}
+
 static void instantiateDependentAMDGPUWavesPerEUAttr(
     Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
     const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
@@ -1690,6 +1713,14 @@ Decl *TemplateDeclInstantiator::VisitFun
       cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
   LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
 
+  ExplicitSpecifier InstantiatedExplicitSpecifier;
+  if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
+    InstantiatedExplicitSpecifier = instantiateExplicitSpecifier(
+        SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide);
+    if (InstantiatedExplicitSpecifier.isInvalid())
+      return nullptr;
+  }
+
   SmallVector<ParmVarDecl *, 4> Params;
   TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
   if (!TInfo)
@@ -1727,8 +1758,9 @@ Decl *TemplateDeclInstantiator::VisitFun
   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(),
+        InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
+        D->getSourceRange().getEnd());
     if (DGuide->isCopyDeductionCandidate())
       cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
     Function->setAccess(D->getAccess());
@@ -1996,6 +2028,12 @@ Decl *TemplateDeclInstantiator::VisitCXX
     }
   }
 
+  ExplicitSpecifier InstantiatedExplicitSpecifier =
+      instantiateExplicitSpecifier(SemaRef, TemplateArgs,
+                                   ExplicitSpecifier::getFromDecl(D), D);
+  if (InstantiatedExplicitSpecifier.isInvalid())
+    return nullptr;
+
   SmallVector<ParmVarDecl *, 4> Params;
   TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
   if (!TInfo)
@@ -2035,11 +2073,10 @@ Decl *TemplateDeclInstantiator::VisitCXX
   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,
+        InstantiatedExplicitSpecifier, 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 +2087,7 @@ Decl *TemplateDeclInstantiator::VisitCXX
   } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
     Method = CXXConversionDecl::Create(
         SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
-        Conversion->isInlineSpecified(), Conversion->isExplicit(),
+        Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
         Conversion->isConstexpr(), Conversion->getEndLoc());
   } else {
     StorageClass SC = D->isStatic() ? SC_Static : SC_None;

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed May  8 20:59:21 2019
@@ -858,7 +858,6 @@ void ASTDeclReader::VisitFunctionDecl(Fu
   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());
@@ -1977,6 +1976,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CX
 }
 
 void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+  D->setExplicitSpecifier(Record.readExplicitSpec());
   VisitFunctionDecl(D);
   D->setIsCopyDeductionCandidate(Record.readInt());
 }
@@ -2002,6 +2002,7 @@ void ASTDeclReader::VisitCXXMethodDecl(C
 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>();
@@ -2027,6 +2028,7 @@ void ASTDeclReader::VisitCXXDestructorDe
 }
 
 void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
+  D->setExplicitSpecifier(Record.readExplicitSpec());
   VisitCXXMethodDecl(D);
 }
 
@@ -3750,10 +3752,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID I
     D = CXXMethodDecl::CreateDeserialized(Context, ID);
     break;
   case DECL_CXX_CONSTRUCTOR:
-    D = CXXConstructorDecl::CreateDeserialized(Context, ID, false);
-    break;
-  case DECL_CXX_INHERITED_CONSTRUCTOR:
-    D = CXXConstructorDecl::CreateDeserialized(Context, ID, true);
+    D = CXXConstructorDecl::CreateDeserialized(Context, ID, Record.readInt());
     break;
   case DECL_CXX_DESTRUCTOR:
     D = CXXDestructorDecl::CreateDeserialized(Context, ID);

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed May  8 20:59:21 2019
@@ -1277,7 +1277,6 @@ void ASTWriter::WriteBlockInfoBlock() {
   RECORD(DECL_CXX_RECORD);
   RECORD(DECL_CXX_METHOD);
   RECORD(DECL_CXX_CONSTRUCTOR);
-  RECORD(DECL_CXX_INHERITED_CONSTRUCTOR);
   RECORD(DECL_CXX_DESTRUCTOR);
   RECORD(DECL_CXX_CONVERSION);
   RECORD(DECL_ACCESS_SPEC);

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed May  8 20:59:21 2019
@@ -535,7 +535,6 @@ void ASTDeclWriter::VisitFunctionDecl(Fu
   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());
@@ -638,7 +637,18 @@ void ASTDeclWriter::VisitFunctionDecl(Fu
   Code = serialization::DECL_FUNCTION;
 }
 
+static void addExplicitSpecifier(ExplicitSpecifier ES,
+                                 ASTRecordWriter &Record) {
+  uint64_t Kind = static_cast<uint64_t>(ES.getKind());
+  Kind = Kind << 1 | static_cast<bool>(ES.getExpr());
+  Record.push_back(Kind);
+  if (ES.getExpr()) {
+    Record.AddStmt(ES.getExpr());
+  }
+}
+
 void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
+  addExplicitSpecifier(D->getExplicitSpecifier(), Record);
   VisitFunctionDecl(D);
   Record.push_back(D->isCopyDeductionCandidate());
   Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
@@ -1331,19 +1341,15 @@ void ASTDeclWriter::VisitCXXMethodDecl(C
 }
 
 void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+  Record.push_back(D->getTraillingAllocKind());
+  addExplicitSpecifier(D->getExplicitSpecifier(), Record);
   if (auto Inherited = D->getInheritedConstructor()) {
     Record.AddDeclRef(Inherited.getShadowDecl());
     Record.AddDeclRef(Inherited.getConstructor());
-    Code = serialization::DECL_CXX_INHERITED_CONSTRUCTOR;
-  } else {
-    Code = serialization::DECL_CXX_CONSTRUCTOR;
   }
 
   VisitCXXMethodDecl(D);
-
-  Code = D->isInheritingConstructor()
-             ? serialization::DECL_CXX_INHERITED_CONSTRUCTOR
-             : serialization::DECL_CXX_CONSTRUCTOR;
+  Code = serialization::DECL_CXX_CONSTRUCTOR;
 }
 
 void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
@@ -1357,6 +1363,7 @@ void ASTDeclWriter::VisitCXXDestructorDe
 }
 
 void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
+  addExplicitSpecifier(D->getExplicitSpecifier(), Record);
   VisitCXXMethodDecl(D);
   Code = serialization::DECL_CXX_CONVERSION;
 }
@@ -2156,7 +2163,6 @@ void ASTWriter::WriteDeclAbbrevs() {
   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

Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp Wed May  8 20:59:21 2019
@@ -71,7 +71,7 @@ extern A(int(&)[26]) -> A<int>;
 #endif
 mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}}
 virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}}
-const A(int(&)[28]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}}
+const A(int(&)[31]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}}
 
 const volatile static constexpr inline A(int(&)[29]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static inline constexpr const volatile'}}
 

Modified: cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp Wed May  8 20:59:21 2019
@@ -3,14 +3,14 @@
 // The same restrictions apply to the parameter-declaration-clause of a
 // deduction guide as in a function declaration.
 template<typename T> struct A {};
-A(void) -> A<int>; // ok
+A(void) -> A<int>; // expected-note {{previous}}
 A(void, int) -> A<int>; // expected-error {{'void' must be the first and only parameter if specified}}
 
-// We interpret this as also extending to the validity of redeclarations. It's
-// a bit of a stretch (OK, a lot of a stretch) but it gives desirable answers.
-A() -> A<int>; // ok, redeclaration
+A() -> A<int>; // expected-error {{redeclaration of deduction guide}}
+// expected-note at -1 {{previous}}
 
 A() -> A<int>; // expected-note {{previous}}
+// expected-error at -1 {{redeclaration of deduction guide}}
 A() -> A<float>; // FIXME: "functions" is a poor term. expected-error {{functions that differ only in their return type cannot be overloaded}}
 
 template<typename T> A(T) -> A<typename T::foo>;

Added: cfe/trunk/test/PCH/cxx-explicit-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx-explicit-specifier.cpp?rev=360311&view=auto
==============================================================================
--- cfe/trunk/test/PCH/cxx-explicit-specifier.cpp (added)
+++ cfe/trunk/test/PCH/cxx-explicit-specifier.cpp Wed May  8 20:59:21 2019
@@ -0,0 +1,124 @@
+// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t-cxx2a
+// RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
+
+#ifndef USE_PCH
+namespace inheriting_constructor {
+  struct S {};
+
+  template<typename X, typename Y> struct T {
+    template<typename A>
+    explicit((Y{}, true)) T(A &&a) {}
+  };
+
+  template<typename X, typename Y> struct U : T<X, Y> {
+    using T<X, Y>::T;
+  };
+
+  U<S, char> foo(char ch) {
+    return U<S, char>(ch);
+  }
+}
+#else
+namespace inheriting_constructor {
+U<S, char> a = foo('0');
+}
+
+//CHECK: explicit((char{} , true))
+
+#endif
+
+namespace basic {
+#ifndef USE_PCH
+
+struct B {};
+
+struct A {
+  explicit A(int);
+  explicit(false) operator bool();
+  explicit(true) operator B();
+};
+#else
+//expected-note at -6+ {{candidate constructor}}
+//expected-note at -9+ {{candidate constructor}}
+//expected-note at -6+ {{candidate function}}
+
+//CHECK: explicit{{ +}}A(
+//CHECK-NEXT: explicit(false){{ +}}operator
+//CHECK-NEXT: explicit(true){{ +}}operator
+A a = 0; //expected-error {{no viable conversion}}
+A a1(0);
+
+bool b = a1;
+B b1 = a1; //expected-error {{no viable conversion}}
+
+#endif
+}
+
+
+namespace templ {
+#ifndef USE_PCH
+
+template<bool b>
+struct B {
+  static constexpr bool value = b;
+};
+
+template<bool b>
+struct A {
+  explicit(b) A(B<b>) {}
+  template<typename T>
+  explicit(b ^ T::value) operator T();
+};
+B<true> b_true;
+B<false> b_false;
+#else
+//expected-note at -8 {{candidate template ignored}}
+//expected-note at -8+ {{explicit constructor}}
+//expected-note at -15+ {{candidate constructor}}
+//expected-note at -8+ {{candidate conversion operator ignored}}
+//expected-note at -9+ {{explicit(bool) specifier resolved to true}}
+//expected-note at -12 {{explicit(bool) specifier resolved to true}}
+//expected-note at -13+ {{candidate deductiong guide ignored}}
+
+//CHECK: explicit(b){{ +}}A
+//CHECK: explicit(b{{ +}}^{{ +}}T::value){{ +}}operator
+
+A a = { b_true }; //expected-error {{class template argument deduction}}
+A a0 = b_true; //expected-error {{no viable constructor or deduction guide}}
+A a_true(b_true);
+A a_false = b_false;
+
+B<true> b = a_true;
+B<true> b1 = a_false; //expected-error {{no viable conversion}}
+B<false> b2(a_true);
+
+#endif
+
+}
+
+namespace guide {
+
+#ifndef USE_PCH
+
+template<typename T>
+struct A {
+  A(T);
+};
+
+template<typename T>
+explicit(true) A(T) -> A<T>;
+
+explicit(false) A(int) -> A<int>;
+
+#else
+//expected-note at -5 {{explicit deduction guide}}
+
+//CHECK: explicit(true){{ +}}A(
+//CHECK: explicit(false){{ +}}A(
+
+A a = { 0.0 }; //expected-error {{explicit deduction guide}}
+A a1 = { 0 };
+
+#endif
+
+}

Modified: cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp (original)
+++ cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp Wed May  8 20:59:21 2019
@@ -115,7 +115,7 @@ static_assert(&r == &x);
 
 #if defined(__cpp_conditional_explicit)
 struct TestConditionalExplicit {
-  explicit(__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
+  explicit(!__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
 };
 TestConditionalExplicit e = 42;
 #endif

Modified: cfe/trunk/test/SemaCXX/cxx2a-compat.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx2a-compat.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx2a-compat.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx2a-compat.cpp Wed May  8 20:59:21 2019
@@ -37,3 +37,23 @@ string u8str = u8"test" u8"test";
 // expected-error at -8 {{cannot initialize a variable of type 'const char *' with an lvalue of type 'const char8_t [6]'}}
 // expected-error at -8 {{no viable conversion from 'const char8_t [9]' to 'string'}}
 #endif
+
+template<bool b>
+struct C {
+  explicit(C)(int);
+};
+#if __cplusplus <= 201703L
+// expected-warning at -3 {{this expression will be parsed as explicit(bool) in C++2a}}
+#if defined(__cpp_conditional_explicit)
+#error "the feature test macro __cpp_conditional_explicit isn't correct"
+#endif
+#else
+// expected-error at -8 {{does not refer to a value}}
+// expected-error at -9 {{expected member name or ';'}}
+// expected-error at -10 {{expected ')'}}
+// expected-note at -12 {{declared here}}
+// expected-note at -12 {{to match this '('}}
+#if !defined(__cpp_conditional_explicit) || __cpp_conditional_explicit != 201806L
+#error "the feature test macro __cpp_conditional_explicit isn't correct"
+#endif
+#endif
\ No newline at end of file

Added: cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp?rev=360311&view=auto
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp (added)
+++ cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp Wed May  8 20:59:21 2019
@@ -0,0 +1,719 @@
+// 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 special_cases
+{
+
+template<int a>
+struct A {
+// expected-note at -1+ {{candidate constructor}}
+  explicit(1 << a)
+// expected-note at -1 {{negative shift count -1}}
+// expected-error at -2 {{explicit specifier argument is not a constant expression}}
+  A(int);
+};
+
+A<-1> a(0);
+// expected-error at -1 {{no matching constructor}}
+// expected-note at -2 {{in instantiation of template class}}
+
+template<int a>
+struct B {
+  explicit(b)
+  // expected-error at -1 {{use of undeclared identifier}}
+  B(int);
+};
+
+template<int a>
+struct B1 {
+  explicit(a +)
+  // expected-error at -1 {{expected expression}}
+  B1(int);
+};
+
+struct B2 {
+  explicit(false) explicit
+  B2(int);
+  // expected-error at -2 {{duplicate 'explicit' declaration specifier}}
+};
+
+template<int a>
+  struct C {
+  // expected-note at -1 {{candidate constructor}} expected-note at -1 {{candidate constructor}}
+  // expected-note at -2 {{candidate constructor}} expected-note at -2 {{candidate constructor}}
+  explicit(a == 0)
+C(int),
+C(double);
+};
+
+C<0> c0 = 0.0; // expected-error {{no viable conversion}}
+C<0> c1 = 0; // expected-error {{no viable conversion}}
+C<1> c2 = 0.0;
+C<1> c3 = 0;
+
+explicit(false) void f(int);// expected-error {{'explicit' can only be specified inside the class definition}}
+
+struct D {
+  explicit(false) void f(int);// expected-error {{'explicit' can only be applied to a constructor or conversion function}}
+};
+
+template <typename T> struct E {
+  // expected-note at -1+ {{candidate constructor}}
+  explicit((T{}, false))
+  // expected-error at -1 {{illegal initializer type 'void'}}
+  E(int);
+};
+
+E<void> e = 1;
+// expected-error at -1 {{no viable conversion}}
+// expected-note at -2 {{in instantiation of}}
+
+}
+
+namespace trailling_object {
+
+template<bool b>
+struct B {
+  explicit(b) B(int) {}
+};
+
+template<bool b>
+struct A : B<b> {
+  explicit(b) A(int) : B<b>(0) {}
+};
+
+A<true> a(0);
+
+}
+
+namespace constructor1 {
+
+template<bool b>
+  struct A {
+    // expected-note at -1+ {{candidate constructor}}
+    // expected-note at -2+ {{candidate function}}
+    explicit(b) A(int, int = 0);
+  // expected-note at -1+ {{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 constructor2 {
+
+template<bool a, typename T1>
+struct A {
+  // expected-note at -1 {{candidate constructor}} expected-note at -1 {{candidate constructor}}
+  // expected-note at -2 {{candidate constructor}} expected-note at -2 {{candidate constructor}}
+  template<typename T2>
+  explicit(a ^ is_same<T1, T2>::value)
+  // expected-note at -1+ {{explicit(bool) specifier resolved to true}}
+  A(T2) {}
+  // expected-note at -1+ {{explicit constructor declared here}}
+  // expected-note at -2+ {{candidate constructor ignored}}
+};
+
+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 constructor_sfinae {
+
+template<bool a>
+struct A {
+  // expected-note at -1+ {{candidate constructor}}
+  template<typename T>
+  explicit(enable_ifv<is_same<int, T>::value, a>::value)
+  //expected-note at -1 {{explicit(bool) specifier resolved to true}}
+  A(T) {}
+  // expected-note at -1+ {{substitution failure}}
+  // expected-note at -2 {{candidate constructor ignored}}
+  // expected-note at -3 {{explicit constructor declared here}}
+  template<typename T, bool c = true>
+  explicit(enable_ifv<is_same<bool, T>::value, a>::value)
+  //expected-note at -1 {{explicit(bool) specifier resolved to true}}
+  A(T) {}
+  // expected-note at -1+ {{substitution failure}}
+  // expected-note at -2 {{candidate constructor ignored}}
+  // expected-note at -3 {{explicit constructor declared here}}
+};
+
+A<true> a0 = 0.0; // expected-error {{no viable conversion}}
+A<true> a1( 0.0); // expected-error {{no matching constructor}}
+A<true> a4{ 0.0}; // expected-error {{no matching constructor}}
+A<true> a7 = { 0.0}; // expected-error {{no matching constructor}}
+
+A<true> b0 = 0; // expected-error {{no viable conversion}}
+A<true> b1( 0);
+A<true> b4{ 0};
+A<true> b7 = { 0}; // expected-error {{chosen constructor is explicit}}
+
+A<false> c0 = 0;
+A<false> c1( 0);
+A<false> c4{ 0};
+A<false> c7 = { 0};
+
+A<true> d0 = true; // expected-error {{no viable conversion}}
+A<true> d1( true);
+A<true> d4{ true};
+A<true> d7 = { true}; // expected-error {{chosen constructor is explicit}}
+
+}
+
+namespace conversion {
+
+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 conversion2 {
+
+struct B {};
+// expected-note at -1+ {{candidate constructor}}
+template<bool a>
+struct A {
+  template<typename T2>
+  explicit(enable_ifv<is_same<B, T2>::value, a>::value)
+  // expected-note at -1+ {{explicit(bool) specifier resolved to true}}
+  operator T2() { return T2(); };
+  // expected-note at -1+ {{substitution failure}}
+  // expected-note at -2+ {{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 parameter_pack {
+
+template<typename T>
+struct A {
+  // expected-note at -1+ {{candidate constructor}}
+  // expected-note at -2+ {{candidate function}}
+  template<typename ... Ts>
+  explicit((is_same<T, Ts>::value && ...))
+  // expected-note at -1 {{explicit(bool) specifier resolved to true}}
+  A(Ts...);
+  // expected-note at -1 {{candidate constructor}}
+  // expected-note at -2 {{explicit constructor}}
+};
+
+template<typename T>
+template<typename ... Ts>
+A<T>::A(Ts ...) {}
+
+void f() {
+
+A<int> a0 = 0; // expected-error {{no viable conversion}}
+A<int> a1( 0, 1);
+A<int> a2{ 0, 1};
+A<int> a3 = { 0, 1}; // expected-error {{chosen constructor is explicit}}
+
+a1 = 0; // expected-error {{no viable overloaded '='}}
+a2 = { 0, 1}; // expected-error {{no viable overloaded '='}}
+
+A<double> b0 = 0;
+A<double> b1( 0, 1);
+A<double> b2{ 0, 1};
+A<double> b3 = { 0, 1};
+
+b1 = 0;
+b2 = { 0, 1};
+
+}
+
+}
+
+namespace deduction_guide {
+
+template<bool b>
+struct B {};
+
+B<true> b_true;
+B<false> b_false;
+
+template<typename T>
+struct nondeduced
+{
+using type = T;
+};
+
+template<typename T1, typename T2, bool b>
+struct A {
+  // expected-note at -1+ {{candidate function}}
+  explicit(false)
+  A(typename nondeduced<T1>::type, typename nondeduced<T2>::type, typename nondeduced<B<b>>::type) {}
+  // expected-note at -1+ {{candidate template ignored}}
+};
+
+template<typename T1, typename T2, bool b>
+explicit(enable_ifv<is_same<T1, T2>::value, b>::value)
+A(T1, T2, B<b>) -> A<T1, T2, b>;
+// expected-note at -1+ {{explicit deduction guide declared here}}
+// expected-note at -2+ {{candidate template ignored}}
+void f() {
+
+A a0( 0.0, 1, b_true); // expected-error {{no viable constructor or deduction guide}}
+A a1{ 0.0, 1, b_true}; // expected-error {{no viable constructor or deduction guide}}
+A a2 = { 0.0, 1, b_true}; // expected-error {{no viable constructor or deduction guide}}
+auto a4 = A( 0.0, 1, b_true); // expected-error {{no viable constructor or deduction guide}}
+auto a5 = A{ 0.0, 1, b_true}; // expected-error {{no viable constructor or deduction guide}}
+
+A b0( 0, 1, b_true);
+A b1{ 0, 1, b_true};
+A b2 = { 0, 1, b_true}; // expected-error {{explicit deduction guide for copy-list-initialization}}
+auto b4 = A( 0, 1, b_true);
+auto b5 = A{ 0, 1, b_true};
+b0 = { 0, 1, b_false}; // expected-error {{no viable overloaded '='}}
+
+A c0( 0, 1, b_false);
+A c1{ 0, 1, b_false};
+A c2 = { 0, 1, b_false};
+auto c4 = A( 0, 1, b_false);
+auto c5 = A{ 0, 1, b_false};
+c2 = { 0, 1, b_false};
+
+}
+
+}
+
+namespace test8 {
+
+template<bool b>
+struct A {
+  //expected-note at -1+ {{candidate function}}
+  template<typename T1, typename T2>
+  explicit(b)
+  A(T1, T2) {}
+  //expected-note at -1 {{explicit constructor declared here}}
+};
+
+template<typename T1, typename T2>
+explicit(!is_same<T1, int>::value)
+A(T1, T2) -> A<!is_same<int, T2>::value>;
+// expected-note at -1+ {{explicit deduction guide declared here}}
+
+template<bool b>
+A<b> v();
+
+void f() {
+
+A a0( 0, 1);
+A a1{ 0, 1};
+A a2 = { 0, 1};
+auto a4 = A( 0, 1);
+auto a5 = A{ 0, 1};
+auto a6(v<false>());
+a6 = { 0, 1};
+
+A b0( 0.0, 1);
+A b1{ 0.0, 1};
+A b2 = { 0.0, 1}; // expected-error {{explicit deduction guide for copy-list-initialization}}
+auto b4 = A( 0.0, 1);
+auto b5 = A{ 0.0, 1};
+
+A c0( 0, 1.0);
+A c1{ 0, 1.0};
+A c2 = { 0, 1.0}; // expected-error {{chosen constructor is explicit}}
+auto c4 = A( 0, 1.0);
+auto c5 = A{ 0, 1.0};
+auto c6(v<true>());
+c0 = { 0, 1.0}; // expected-error {{no viable overloaded '='}}
+
+A d0( 0.0, 1.0);
+A d1{ 0.0, 1.0};
+A d2 = { 0.0, 1.0};  // expected-error {{explicit deduction guide for copy-list-initialization}}
+auto d4 = A( 0.0, 1.0);
+auto d5 = A{ 0.0, 1.0};
+
+}
+
+}
+
+namespace conversion3 {
+
+template<bool b>
+struct A {
+  explicit(!b) operator int();
+  explicit(b) operator bool();
+};
+
+template<bool b>
+A<b>::operator bool() { return false; }
+
+struct B {
+  void f(int);
+  void f(bool);
+};
+
+void f(A<true> a, B b) {
+  b.f(a);
+}
+
+void f1(A<false> a, B b) {
+  b.f(a);
+}
+
+// Taken from 12.3.2p2
+class X { X(); };
+class Y { }; // expected-note+ {{candidate constructor (the implicit}}
+
+template<bool b>
+struct Z {
+  explicit(b) operator X() const;
+  explicit(b) operator Y() const;
+  explicit(b) operator int() const;
+};
+
+void testExplicit()
+{
+Z<true> z;
+// 13.3.1.4p1 & 8.5p16:
+Y y2 = z; // expected-error {{no viable conversion}}
+Y y2b(z);
+Y y3 = (Y)z;
+Y y4 = Y(z);
+Y y5 = static_cast<Y>(z);
+// 13.3.1.5p1 & 8.5p16:
+int i1 = (int)z;
+int i2 = int(z);
+int i3 = static_cast<int>(z);
+int i4(z);
+// 13.3.1.6p1 & 8.5.3p5:
+const Y& y6 = z; // expected-error {{no viable conversion}}
+const int& y7 = z; // expected-error {{no viable conversion}}
+const Y& y8(z);
+const int& y9(z);
+
+// Y is an aggregate, so aggregate-initialization is performed and the
+// conversion function is not considered.
+const Y y10{z}; // expected-error {{excess elements}}
+const Y& y11{z}; // expected-error {{excess elements}} expected-note {{in initialization of temporary}}
+const int& y12{z};
+
+// X is not an aggregate, so constructors are considered,
+// per 13.3.3.1/4 & DR1467.
+const X x1{z};
+const X& x2{z};
+}
+
+struct tmp {};
+
+template<typename T1>
+struct C {
+  template<typename T>
+  explicit(!is_same<T1, T>::value)
+  // expected-note at -1+ {{explicit(bool) specifier resolved to true}}
+  operator T();
+  // expected-note at -1+ {{candidate conversion operator ignored}}
+};
+
+using Bool = C<bool>;
+using Integral = C<int>;
+using Unrelated = C<tmp>;
+
+void testBool() {
+Bool    b;
+Integral n;
+Unrelated u;
+
+(void) (1 + b); // expected-error {{invalid operands to binary expression}}
+(void) (1 + n);
+(void) (1 + u); // expected-error {{invalid operands to binary expression}}
+
+// 5.3.1p9:
+(void) (!b);
+(void) (!n);
+(void) (!u);
+
+// 5.14p1:
+(void) (b && true);
+(void) (n && true);
+(void) (u && true);
+
+// 5.15p1:
+(void) (b || true);
+(void) (n || true);
+(void) (u || true);
+
+// 5.16p1:
+(void) (b ? 0 : 1);
+(void) (n ? 0: 1);
+(void) (u ? 0: 1);
+
+// // 5.19p5:
+// // TODO: After constexpr has been implemented
+
+// 6.4p4:
+if (b) {}
+if (n) {}
+if (u) {}
+
+// 6.4.2p2:
+switch (b) {} // expected-error {{statement requires expression of integer type}}
+switch (n) {} // expected-error {{statement requires expression of integer type}}
+switch (u) {} // expected-error {{statement requires expression of integer type}}
+
+// 6.5.1:
+while (b) {}
+while (n) {}
+while (u) {}
+
+// 6.5.2p1:
+do {} while (b);
+do {} while (n);
+do {} while (u);
+
+// 6.5.3:
+for (;b;) {}
+for (;n;) {}
+for (;u;) {}
+
+// 13.3.1.5p1:
+bool db1(b);
+bool db2(n);
+bool db3(u);
+int di1(b);
+int di2(n);
+int di3(n);
+const bool &direct_cr1(b);
+const bool &direct_cr2(n);
+const bool &direct_cr3(n);
+const int &direct_cr4(b);
+const int &direct_cr5(n);
+const int &direct_cr6(n);
+bool directList1{b};
+bool directList2{n};
+bool directList3{n};
+int directList4{b};
+int directList5{n};
+int directList6{n};
+const bool &directList_cr1{b};
+const bool &directList_cr2{n};
+const bool &directList_cr3{n};
+const int &directList_cr4{b};
+const int &directList_cr5{n};
+const int &directList_cr6{n};
+bool copy1 = b;
+bool copy2 = n;// expected-error {{no viable conversion}}
+bool copyu2 = u;// expected-error {{no viable conversion}}
+int copy3 = b;// expected-error {{no viable conversion}}
+int copy4 = n;
+int copyu4 = u;// expected-error {{no viable conversion}}
+const bool &copy5 = b;
+const bool &copy6 = n;// expected-error {{no viable conversion}}
+const bool &copyu6 = u;// expected-error {{no viable conversion}}
+const int &copy7 = b;// expected-error {{no viable conversion}}
+const int &copy8 = n;
+const int &copyu8 = u;// expected-error {{no viable conversion}}
+bool copyList1 = {b};
+bool copyList2 = {n};// expected-error {{no viable conversion}}
+bool copyListu2 = {u};// expected-error {{no viable conversion}}
+int copyList3 = {b};// expected-error {{no viable conversion}}
+int copyList4 = {n};
+int copyListu4 = {u};// expected-error {{no viable conversion}}
+const bool &copyList5 = {b};
+const bool &copyList6 = {n};// expected-error {{no viable conversion}}
+const bool &copyListu6 = {u};// expected-error {{no viable conversion}}
+const int &copyList7 = {b};// expected-error {{no viable conversion}}
+const int &copyList8 = {n};
+const int &copyListu8 = {u};// expected-error {{no viable conversion}}
+}
+
+}
+
+namespace deduction_guide2 {
+
+template<typename T1 = int, typename T2 = int>
+struct A {
+  // expected-note at -1+ {{candidate template ignored}}
+  explicit(!is_same<T1, T2>::value)
+  // expected-note at -1+ {{explicit(bool) specifier resolved to true}}
+  A(T1 = 0, T2 = 0) {}
+  // expected-note at -1 {{explicit constructor}}
+  // expected-note at -2+ {{candidate deductiong guide ignored}}
+};
+
+A a0 = 0;
+A a1(0, 0);
+A a2{0, 0};
+A a3 = {0, 0};
+
+A b0 = 0.0; // expected-error {{no viable constructor or deduction guide}}
+A b1(0.0, 0.0);
+A b2{0.0, 0.0};
+A b3 = {0.0, 0.0};
+
+A b4 = {0.0, 0}; // expected-error {{explicit constructor}}
+
+template<typename T1, typename T2>
+explicit A(T1, T2) -> A<T1, T2>;
+// expected-note at -1+ {{explicit deduction guide}}
+
+A c0 = 0;
+A c1(0, 0);
+A c2{0, 0};
+A c3 = {0, 0};// expected-error {{explicit deduction guide}}
+
+A d0 = 0.0; // expected-error {{no viable constructor or deduction guide}}
+A d1(0, 0);
+A d2{0, 0};
+A d3 = {0.0, 0.0};// expected-error {{explicit deduction guide}}
+
+}

Modified: cfe/trunk/test/SemaCXX/explicit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/explicit.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/explicit.cpp (original)
+++ cfe/trunk/test/SemaCXX/explicit.cpp Wed May  8 20:59:21 2019
@@ -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);
@@ -34,6 +36,21 @@ B &&b3(0); // expected-error {{could not
 B b4{0};
 B &&b5 = {0}; // expected-error {{chosen constructor is explicit}}
 B &&b6{0};
+
+struct S {
+  template <bool b = true>
+  explicit S();
+};
+
+struct T : S {
+  //  T();
+};
+
+struct U : T {
+  U();
+};
+U::U() {}
+
 }
 
 namespace Conversion {
@@ -183,7 +200,8 @@ namespace Conversion {
     const int &copyList7 = {b};
     const int &copyList8 = {n}; // expected-error {{no viable conversion}}
   }
-  
+
+#if __cplusplus < 201707L
   void testNew()
   {
     // 5.3.4p6:
@@ -200,7 +218,8 @@ namespace Conversion {
     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:

Modified: cfe/trunk/unittests/AST/Language.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/Language.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/Language.cpp (original)
+++ cfe/trunk/unittests/AST/Language.cpp Wed May  8 20:59:21 2019
@@ -34,6 +34,9 @@ ArgVector getBasicRunOptionsForLanguage(
   case Lang_CXX14:
     BasicArgs = {"-std=c++14", "-frtti"};
     break;
+  case Lang_CXX2a:
+    BasicArgs = {"-std=c++2a", "-frtti"};
+    break;
   case Lang_OpenCL:
   case Lang_OBJCXX:
     llvm_unreachable("Not implemented yet!");

Modified: cfe/trunk/unittests/AST/Language.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/Language.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/Language.h (original)
+++ cfe/trunk/unittests/AST/Language.h Wed May  8 20:59:21 2019
@@ -28,6 +28,7 @@ enum Language {
     Lang_CXX,
     Lang_CXX11,
     Lang_CXX14,
+    Lang_CXX2a,
     Lang_OpenCL,
     Lang_OBJCXX
 };

Modified: cfe/trunk/unittests/AST/MatchVerifier.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/MatchVerifier.h?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/MatchVerifier.h (original)
+++ cfe/trunk/unittests/AST/MatchVerifier.h Wed May  8 20:59:21 2019
@@ -108,6 +108,10 @@ testing::AssertionResult MatchVerifier<N
     Args.push_back("-std=c++14");
     FileName = "input.cc";
     break;
+  case Lang_CXX2a:
+    Args.push_back("-std=c++2a");
+    FileName = "input.cc";
+    break;
   case Lang_OpenCL:
     FileName = "input.cl";
     break;

Modified: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp (original)
+++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp Wed May  8 20:59:21 2019
@@ -806,6 +806,26 @@ TEST_F(StructuralEquivalenceTest, Compar
   EXPECT_FALSE(testStructuralMatch(t));
 }
 
+TEST_F(StructuralEquivalenceTest, ExplicitBoolDifferent) {
+  auto Decls = makeNamedDecls("struct foo {explicit(false) foo(int);};",
+                              "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
+  CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<0>(Decls), cxxConstructorDecl(hasName("foo")));
+  CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<1>(Decls), cxxConstructorDecl(hasName("foo")));
+  EXPECT_FALSE(testStructuralMatch(First, Second));
+}
+
+TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) {
+  auto Decls = makeNamedDecls("struct foo {explicit(true) foo(int);};",
+                              "struct foo {explicit(true) foo(int);};", Lang_CXX2a);
+  CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<0>(Decls), cxxConstructorDecl(hasName("foo")));
+  CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<1>(Decls), cxxConstructorDecl(hasName("foo")));
+  EXPECT_TRUE(testStructuralMatch(First, Second));
+}
+
 struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
 
 TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
@@ -853,5 +873,25 @@ TEST_F(StructuralEquivalenceTemplateTest
   EXPECT_FALSE(testStructuralMatch(t));
 }
 
+TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
+  auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
+                              "template <bool b> struct foo {explicit(b) foo(int);};", Lang_CXX2a);
+  CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+  CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+  EXPECT_TRUE(testStructuralMatch(First, Second));
+}
+
+TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
+  auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
+                              "template <bool b> struct foo {explicit(!b) foo(int);};", Lang_CXX2a);
+  CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+  CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
+      get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
+  EXPECT_FALSE(testStructuralMatch(First, Second));
+}
+
 } // end namespace ast_matchers
 } // end namespace clang

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=360311&r1=360310&r2=360311&view=diff
==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Wed May  8 20:59:21 2019
@@ -1002,7 +1002,7 @@ as the draft C++2a standard evolves.
     <tr>
       <td><tt>explicit(bool)</tt></td>
       <td><a href="http://wg21.link/p0892r2">P0892R2</a></td>
-      <td class="none" align="center">No</td>
+      <td class="svn" align="center">SVN</td>
     </tr>
     <!-- San Diego papers -->
     <tr>




More information about the cfe-commits mailing list