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