Index: cfe/trunk/include/clang/AST/Decl.h =================================================================== --- cfe/trunk/include/clang/AST/Decl.h +++ cfe/trunk/include/clang/AST/Decl.h @@ -2369,16 +2369,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: cfe/trunk/include/clang/AST/DeclBase.h =================================================================== --- cfe/trunk/include/clang/AST/DeclBase.h +++ cfe/trunk/include/clang/AST/DeclBase.h @@ -1472,10 +1472,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; @@ -1523,7 +1519,7 @@ }; /// 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 @@ /// 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 Index: cfe/trunk/include/clang/AST/DeclCXX.h =================================================================== --- cfe/trunk/include/clang/AST/DeclCXX.h +++ cfe/trunk/include/clang/AST/DeclCXX.h @@ -1993,6 +1993,50 @@ } }; +/// Store information needed for an explicit specifier. +/// used by CXXDeductionGuideDecl, CXXConstructorDecl and CXXConversionDecl. +class ExplicitSpecifier { + llvm::PointerIntPair 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 @@ 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 @@ /// \endcode class CXXConstructorDecl final : public CXXMethodDecl, - private llvm::TrailingObjects { + private llvm::TrailingObjects { // This class stores some data in DeclContext::CXXConstructorDeclBits // to save some space. Use the provided accessors to access it. @@ -2511,28 +2561,74 @@ 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) const { + return CXXConstructorDeclBits.IsInheritingConstructor; + } + size_t numTrailingObjects(OverloadToken) const { + return CXXConstructorDeclBits.HasTrailingExplicitSpecifier; + } + + ExplicitSpecifier getExplicitSpecifierInternal() const { + if (CXXConstructorDeclBits.HasTrailingExplicitSpecifier) + return *getCanonicalDecl()->getTrailingObjects(); + 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() = ES; + else + CXXConstructorDeclBits.IsSimpleExplicit = ES.isExplicit(); + } + + enum TraillingAllocKind { + TAKInheritsConstructor = 1, + TAKHasTailExplicit = 1 << 1, + }; + + uint64_t getTraillingAllocKind() const { + return numTrailingObjects(OverloadToken()) | + (numTrailingObjects(OverloadToken()) << 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 @@ 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 @@ 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()->getReturnType(); Index: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h @@ -6171,6 +6171,9 @@ 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(); } Index: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td @@ -150,6 +150,8 @@ def warn_duplicate_declspec : Warning<"%sub{duplicate_declspec}0">, InGroup; +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< Index: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td @@ -33,6 +33,10 @@ let CategoryName = "Parse Issue" in { +def warn_cxx2a_compat_explicit_bool : Warning< + "this expression will be parsed as explicit(bool) in C++2a">, + InGroup, DefaultIgnore; + def ext_empty_translation_unit : Extension< "ISO C requires a translation unit to contain at least one declaration">, InGroup>; Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -83,11 +83,11 @@ "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, DefaultError, SFINAEFailure; @@ -2115,9 +2115,8 @@ "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 @@ "| 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< Index: cfe/trunk/include/clang/Basic/Specifiers.h =================================================================== --- cfe/trunk/include/clang/Basic/Specifiers.h +++ cfe/trunk/include/clang/Basic/Specifiers.h @@ -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, Index: cfe/trunk/include/clang/Sema/DeclSpec.h =================================================================== --- cfe/trunk/include/clang/Sema/DeclSpec.h +++ cfe/trunk/include/clang/Sema/DeclSpec.h @@ -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 @@ 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 @@ Expr *ExprRep; }; + /// ExplicitSpecifier - Store information about explicit spicifer. + ExplicitSpecifier FS_explicit_specifier; + // attributes. ParsedAttributes Attrs; @@ -393,6 +396,7 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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); Index: cfe/trunk/include/clang/Sema/Overload.h =================================================================== --- cfe/trunk/include/clang/Sema/Overload.h +++ cfe/trunk/include/clang/Sema/Overload.h @@ -705,6 +705,11 @@ /// 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, Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -2743,7 +2743,8 @@ 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 @@ 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 @@ FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, - bool PartialOverloading = false, + bool PartialOverloading = false, bool AllowExplicit = true, ADLCallKind IsADLCandidate = ADLCallKind::NotADL); bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate, ArrayRef ParamTypes, @@ -2916,20 +2918,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, @@ -10158,6 +10156,14 @@ 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); Index: cfe/trunk/include/clang/Serialization/ASTBitCodes.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h @@ -1441,9 +1441,6 @@ /// A CXXConstructorDecl record. DECL_CXX_CONSTRUCTOR, - /// A CXXConstructorDecl record for an inherited constructor. - DECL_CXX_INHERITED_CONSTRUCTOR, - /// A CXXDestructorDecl record. DECL_CXX_DESTRUCTOR, Index: cfe/trunk/include/clang/Serialization/ASTReader.h =================================================================== --- cfe/trunk/include/clang/Serialization/ASTReader.h +++ cfe/trunk/include/clang/Serialization/ASTReader.h @@ -2430,6 +2430,14 @@ ID); } + ExplicitSpecifier readExplicitSpec() { + uint64_t Kind = readInt(); + bool HasExpr = Kind & 0x1; + Kind = Kind >> 1; + return ExplicitSpecifier(HasExpr ? readExpr() : nullptr, + static_cast(Kind)); + } + void readExceptionSpec(SmallVectorImpl &ExceptionStorage, FunctionProtoType::ExceptionSpecInfo &ESI) { return Reader->readExceptionSpec(*F, ExceptionStorage, ESI, Record, Idx); Index: cfe/trunk/lib/AST/ASTImporter.cpp =================================================================== --- cfe/trunk/lib/AST/ASTImporter.cpp +++ cfe/trunk/lib/AST/ASTImporter.cpp @@ -3076,11 +3076,20 @@ // Create the imported function. FunctionDecl *ToFunction = nullptr; if (auto *FromConstructor = dyn_cast(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( - 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, + ExplicitSpecifier( + ExplicitExpr, + FromConstructor->getExplicitSpecifier().getKind()), + D->isInlineSpecified(), D->isImplicit(), D->isConstexpr())) return ToFunction; } else if (CXXDestructorDecl *FromDtor = dyn_cast(D)) { @@ -3106,10 +3115,19 @@ ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg); } else if (CXXConversionDecl *FromConversion = dyn_cast(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( ToFunction, D, Importer.getToContext(), cast(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(D)) { if (GetImportedOrCreateDecl( Index: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp +++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp @@ -982,13 +982,15 @@ if (auto *Constructor1 = dyn_cast(Method1)) { auto *Constructor2 = cast(Method2); - if (Constructor1->isExplicit() != Constructor2->isExplicit()) + if (!Constructor1->getExplicitSpecifier().isEquivalent( + Constructor2->getExplicitSpecifier())) return false; } if (auto *Conversion1 = dyn_cast(Method1)) { auto *Conversion2 = cast(Method2); - if (Conversion1->isExplicit() != Conversion2->isExplicit()) + if (!Conversion1->getExplicitSpecifier().isEquivalent( + Conversion2->getExplicitSpecifier())) return false; if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(), Conversion2->getConversionType())) Index: cfe/trunk/lib/AST/Decl.cpp =================================================================== --- cfe/trunk/lib/AST/Decl.cpp +++ cfe/trunk/lib/AST/Decl.cpp @@ -2713,7 +2713,6 @@ FunctionDeclBits.SClass = S; FunctionDeclBits.IsInline = isInlineSpecified; FunctionDeclBits.IsInlineSpecified = isInlineSpecified; - FunctionDeclBits.IsExplicitSpecified = false; FunctionDeclBits.IsVirtualAsWritten = false; FunctionDeclBits.IsPure = false; FunctionDeclBits.HasInheritedPrototype = false; Index: cfe/trunk/lib/AST/DeclCXX.cpp =================================================================== --- cfe/trunk/lib/AST/DeclCXX.cpp +++ cfe/trunk/lib/AST/DeclCXX.cpp @@ -1879,19 +1879,47 @@ 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(Function)->getExplicitSpecifier(); + case Decl::Kind::CXXConversion: + return cast(Function)->getExplicitSpecifier(); + case Decl::Kind::CXXDeductionGuide: + return cast(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 @@ 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(Inherited)); setImplicit(isImplicitlyDeclared); + CXXConstructorDeclBits.HasTrailingExplicitSpecifier = ES.getExpr() ? 1 : 0; if (Inherited) *getTrailingObjects() = Inherited; - setExplicitSpecified(isExplicitSpecified); + setExplicitSpecifier(ES); } void CXXConstructorDecl::anchor() {} CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, unsigned ID, - bool Inherited) { - unsigned Extra = additionalSizeToAlloc(Inherited); + uint64_t AllocKind) { + bool hasTraillingExplicit = static_cast(AllocKind & TAKHasTailExplicit); + bool isInheritingConstructor = + static_cast(AllocKind & TAKInheritsConstructor); + unsigned Extra = + additionalSizeToAlloc( + 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(Inherited ? 1 : 0); - return new (C, RD, Extra) CXXConstructorDecl( - C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline, - isImplicitlyDeclared, isConstexpr, Inherited); + additionalSizeToAlloc( + 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 @@ 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 { Index: cfe/trunk/lib/AST/DeclPrinter.cpp =================================================================== --- cfe/trunk/lib/AST/DeclPrinter.cpp +++ cfe/trunk/lib/AST/DeclPrinter.cpp @@ -566,6 +566,21 @@ } } +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 @@ 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); Index: cfe/trunk/lib/Frontend/InitPreprocessor.cpp =================================================================== --- cfe/trunk/lib/Frontend/InitPreprocessor.cpp +++ cfe/trunk/lib/Frontend/InitPreprocessor.cpp @@ -540,6 +540,8 @@ 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"); Index: cfe/trunk/lib/Parse/ParseDecl.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseDecl.cpp +++ cfe/trunk/lib/Parse/ParseDecl.cpp @@ -2480,12 +2480,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(); @@ -3004,9 +3004,13 @@ 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 . @@ -3558,9 +3562,34 @@ 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(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 @@ // 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(); Index: cfe/trunk/lib/Sema/DeclSpec.cpp =================================================================== --- cfe/trunk/lib/Sema/DeclSpec.cpp +++ cfe/trunk/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; @@ -959,17 +959,24 @@ } 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 @@ // 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(); } Index: cfe/trunk/lib/Sema/SemaCodeComplete.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCodeComplete.cpp +++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp @@ -4970,7 +4970,8 @@ 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()), Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -5725,7 +5725,7 @@ 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 @@ 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 @@ 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) { @@ -8054,13 +8054,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, @@ -8421,7 +8421,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()) { @@ -8604,20 +8604,20 @@ // 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(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(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()); + << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange()); } } Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp @@ -657,14 +657,13 @@ 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(New); - if (NewGuide && NewGuide->isExplicitSpecified() != - cast(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(New) && + !New->isFunctionTemplateSpecialization()) { + Diag(New->getLocation(), diag::err_deduction_guide_redeclared); Diag(Old->getLocation(), diag::note_previous_declaration); } @@ -8594,12 +8593,12 @@ 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 @@ }; } +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 @@ = 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 @@ 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 @@ // 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 @@ // 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(); Index: cfe/trunk/lib/Sema/SemaInit.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp +++ cfe/trunk/lib/Sema/SemaInit.cpp @@ -3763,9 +3763,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 +3780,8 @@ 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 @@ else Conv = cast(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 @@ 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 @@ // 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 @@ 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 @@ 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 @@ OverloadCandidateSet::iterator Best; bool HasAnyDeductionGuide = false; + bool AllowExplicit = !Kind.isCopyInit() || ListInit; auto tryToResolveOverload = [&](bool OnlyListConstructors) -> OverloadingResult { @@ -9361,7 +9368,7 @@ // 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 @@ 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); }; Index: cfe/trunk/lib/Sema/SemaLambda.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaLambda.cpp +++ cfe/trunk/lib/Sema/SemaLambda.cpp @@ -1325,7 +1325,7 @@ 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 @@ 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); Index: cfe/trunk/lib/Sema/SemaLookup.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaLookup.cpp +++ cfe/trunk/lib/Sema/SemaLookup.cpp @@ -3041,10 +3041,11 @@ 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(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) Index: cfe/trunk/lib/Sema/SemaOverload.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaOverload.cpp +++ cfe/trunk/lib/Sema/SemaOverload.cpp @@ -3242,10 +3242,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); } } @@ -3372,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); } } } @@ -3410,14 +3415,13 @@ 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 @@ } 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 @@ // 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 @@ 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 @@ /// \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"); @@ -6150,13 +6153,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; @@ -6170,6 +6171,15 @@ } } + 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 @@ 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; @@ -6808,9 +6818,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 @@ -6915,14 +6926,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(); @@ -7081,6 +7089,13 @@ "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 @@ /// 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"); @@ -7137,7 +7149,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 @@ -8991,12 +9003,14 @@ AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, /*SupressUserConversions=*/false, PartialOverloading, - /*AllowExplicit=*/false, ADLCallKind::UsesADL); + /*AllowExplicitConversions*/ false, + /*AllowExplicit*/ true, ADLCallKind::UsesADL); } else { - AddTemplateOverloadCandidate(cast(*I), FoundDecl, - ExplicitTemplateArgs, Args, CandidateSet, - /*SupressUserConversions=*/false, - PartialOverloading, ADLCallKind::UsesADL); + AddTemplateOverloadCandidate( + cast(*I), FoundDecl, ExplicitTemplateArgs, Args, + CandidateSet, + /*SuppressUserConversions=*/false, PartialOverloading, + /*AllowExplicit*/true, ADLCallKind::UsesADL); } } } @@ -10327,6 +10341,33 @@ << 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(Cand->Function)->getExplicitSpecifier(); + DeclName = "constructor"; + break; + case Decl::Kind::CXXConversion: + ES = cast(Cand->Function)->getExplicitSpecifier(); + DeclName = "conversion operator"; + break; + case Decl::Kind::CXXDeductionGuide: + ES = cast(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 @@ 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 @@ // 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); } else if ((Method = dyn_cast(Func))) { // If explicit template arguments were provided, we can't call a // non-template member function. Index: cfe/trunk/lib/Sema/SemaTemplate.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp +++ cfe/trunk/lib/Sema/SemaTemplate.cpp @@ -1156,7 +1156,7 @@ if (DS.isVirtualSpecified()) EmitDiag(DS.getVirtualSpecLoc()); - if (DS.isExplicitSpecified()) + if (DS.hasExplicitSpecifier()) EmitDiag(DS.getExplicitSpecLoc()); if (DS.isNoreturnSpecified()) @@ -1836,8 +1836,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()); } @@ -1866,8 +1866,8 @@ 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 @@ } 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 @@ // 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); Index: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -366,6 +366,29 @@ 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 @@ cast(Owner)->isDefinedOutsideFunctionOrMethod()); LocalInstantiationScope Scope(SemaRef, MergeWithParentScope); + ExplicitSpecifier InstantiatedExplicitSpecifier; + if (auto *DGuide = dyn_cast(D)) { + InstantiatedExplicitSpecifier = instantiateExplicitSpecifier( + SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide); + if (InstantiatedExplicitSpecifier.isInvalid()) + return nullptr; + } + SmallVector Params; TypeSourceInfo *TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -1727,8 +1758,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(), + InstantiatedExplicitSpecifier, NameInfo, T, TInfo, + D->getSourceRange().getEnd()); if (DGuide->isCopyDeductionCandidate()) cast(Function)->setIsCopyDeductionCandidate(); Function->setAccess(D->getAccess()); @@ -1996,6 +2028,12 @@ } } + ExplicitSpecifier InstantiatedExplicitSpecifier = + instantiateExplicitSpecifier(SemaRef, TemplateArgs, + ExplicitSpecifier::getFromDecl(D), D); + if (InstantiatedExplicitSpecifier.isInvalid()) + return nullptr; + SmallVector Params; TypeSourceInfo *TInfo = SubstFunctionType(D, Params); if (!TInfo) @@ -2035,11 +2073,10 @@ 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, + InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false, + Constructor->isConstexpr()); Method->setRangeEnd(Constructor->getEndLoc()); } else if (CXXDestructorDecl *Destructor = dyn_cast(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, @@ -2050,7 +2087,7 @@ } else if (CXXConversionDecl *Conversion = dyn_cast(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; Index: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp +++ cfe/trunk/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()); @@ -1977,6 +1976,7 @@ } void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) { + D->setExplicitSpecifier(Record.readExplicitSpec()); VisitFunctionDecl(D); D->setIsCopyDeductionCandidate(Record.readInt()); } @@ -2002,6 +2002,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(); @@ -2027,6 +2028,7 @@ } void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) { + D->setExplicitSpecifier(Record.readExplicitSpec()); VisitCXXMethodDecl(D); } @@ -3750,10 +3752,7 @@ 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); Index: cfe/trunk/lib/Serialization/ASTWriter.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp +++ cfe/trunk/lib/Serialization/ASTWriter.cpp @@ -1277,7 +1277,6 @@ 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); Index: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp =================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp +++ cfe/trunk/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()); @@ -638,7 +637,18 @@ Code = serialization::DECL_FUNCTION; } +static void addExplicitSpecifier(ExplicitSpecifier ES, + ASTRecordWriter &Record) { + uint64_t Kind = static_cast(ES.getKind()); + Kind = Kind << 1 | static_cast(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::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::VisitCXXConversionDecl(CXXConversionDecl *D) { + addExplicitSpecifier(D->getExplicitSpecifier(), Record); VisitCXXMethodDecl(D); Code = serialization::DECL_CXX_CONVERSION; } @@ -2156,7 +2163,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: cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp =================================================================== --- cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp +++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p1.cpp @@ -71,7 +71,7 @@ #endif mutable A(int(&)[27]) -> A; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}} virtual A(int(&)[28]) -> A; // expected-error {{'virtual' can only appear on non-static member functions}} -const A(int(&)[28]) -> A; // expected-error {{deduction guide cannot be declared 'const'}} +const A(int(&)[31]) -> A; // expected-error {{deduction guide cannot be declared 'const'}} const volatile static constexpr inline A(int(&)[29]) -> A; // expected-error {{deduction guide cannot be declared 'static inline constexpr const volatile'}} Index: cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp =================================================================== --- cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp +++ cfe/trunk/test/CXX/temp/temp.deduct.guide/p3.cpp @@ -3,14 +3,14 @@ // The same restrictions apply to the parameter-declaration-clause of a // deduction guide as in a function declaration. template struct A {}; -A(void) -> A; // ok +A(void) -> A; // expected-note {{previous}} A(void, int) -> A; // 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; // ok, redeclaration +A() -> A; // expected-error {{redeclaration of deduction guide}} +// expected-note@-1 {{previous}} A() -> A; // expected-note {{previous}} +// expected-error@-1 {{redeclaration of deduction guide}} A() -> A; // FIXME: "functions" is a poor term. expected-error {{functions that differ only in their return type cannot be overloaded}} template A(T) -> A; Index: cfe/trunk/test/PCH/cxx-explicit-specifier.cpp =================================================================== --- cfe/trunk/test/PCH/cxx-explicit-specifier.cpp +++ cfe/trunk/test/PCH/cxx-explicit-specifier.cpp @@ -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 struct T { + template + explicit((Y{}, true)) T(A &&a) {} + }; + + template struct U : T { + using T::T; + }; + + U foo(char ch) { + return U(ch); + } +} +#else +namespace inheriting_constructor { +U 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@-6+ {{candidate constructor}} +//expected-note@-9+ {{candidate constructor}} +//expected-note@-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 +struct B { + static constexpr bool value = b; +}; + +template +struct A { + explicit(b) A(B) {} + template + explicit(b ^ T::value) operator T(); +}; +B b_true; +B b_false; +#else +//expected-note@-8 {{candidate template ignored}} +//expected-note@-8+ {{explicit constructor}} +//expected-note@-15+ {{candidate constructor}} +//expected-note@-8+ {{candidate conversion operator ignored}} +//expected-note@-9+ {{explicit(bool) specifier resolved to true}} +//expected-note@-12 {{explicit(bool) specifier resolved to true}} +//expected-note@-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 b = a_true; +B b1 = a_false; //expected-error {{no viable conversion}} +B b2(a_true); + +#endif + +} + +namespace guide { + +#ifndef USE_PCH + +template +struct A { + A(T); +}; + +template +explicit(true) A(T) -> A; + +explicit(false) A(int) -> A; + +#else +//expected-note@-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 + +} Index: cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp =================================================================== --- cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp +++ cfe/trunk/test/SemaCXX/builtin-is-constant-evaluated.cpp @@ -115,7 +115,7 @@ #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 Index: cfe/trunk/test/SemaCXX/cxx2a-compat.cpp =================================================================== --- cfe/trunk/test/SemaCXX/cxx2a-compat.cpp +++ cfe/trunk/test/SemaCXX/cxx2a-compat.cpp @@ -37,3 +37,23 @@ // expected-error@-8 {{cannot initialize a variable of type 'const char *' with an lvalue of type 'const char8_t [6]'}} // expected-error@-8 {{no viable conversion from 'const char8_t [9]' to 'string'}} #endif + +template +struct C { + explicit(C)(int); +}; +#if __cplusplus <= 201703L +// expected-warning@-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@-8 {{does not refer to a value}} +// expected-error@-9 {{expected member name or ';'}} +// expected-error@-10 {{expected ')'}} +// expected-note@-12 {{declared here}} +// expected-note@-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 Index: cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp =================================================================== --- cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp +++ cfe/trunk/test/SemaCXX/cxx2a-explicit-bool.cpp @@ -0,0 +1,719 @@ +// 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 special_cases +{ + +template +struct A { +// expected-note@-1+ {{candidate constructor}} + explicit(1 << a) +// expected-note@-1 {{negative shift count -1}} +// expected-error@-2 {{explicit specifier argument is not a constant expression}} + A(int); +}; + +A<-1> a(0); +// expected-error@-1 {{no matching constructor}} +// expected-note@-2 {{in instantiation of template class}} + +template +struct B { + explicit(b) + // expected-error@-1 {{use of undeclared identifier}} + B(int); +}; + +template +struct B1 { + explicit(a +) + // expected-error@-1 {{expected expression}} + B1(int); +}; + +struct B2 { + explicit(false) explicit + B2(int); + // expected-error@-2 {{duplicate 'explicit' declaration specifier}} +}; + +template + struct C { + // expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}} + // expected-note@-2 {{candidate constructor}} expected-note@-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 struct E { + // expected-note@-1+ {{candidate constructor}} + explicit((T{}, false)) + // expected-error@-1 {{illegal initializer type 'void'}} + E(int); +}; + +E e = 1; +// expected-error@-1 {{no viable conversion}} +// expected-note@-2 {{in instantiation of}} + +} + +namespace trailling_object { + +template +struct B { + explicit(b) B(int) {} +}; + +template +struct A : B { + explicit(b) A(int) : B(0) {} +}; + +A a(0); + +} + +namespace constructor1 { + +template + struct A { + // expected-note@-1+ {{candidate constructor}} + // expected-note@-2+ {{candidate function}} + explicit(b) A(int, int = 0); + // expected-note@-1+ {{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 constructor2 { + +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}} + A(T2) {} + // expected-note@-1+ {{explicit constructor declared here}} + // expected-note@-2+ {{candidate constructor ignored}} +}; + +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 constructor_sfinae { + +template +struct A { + // expected-note@-1+ {{candidate constructor}} + template + explicit(enable_ifv::value, a>::value) + //expected-note@-1 {{explicit(bool) specifier resolved to true}} + A(T) {} + // expected-note@-1+ {{substitution failure}} + // expected-note@-2 {{candidate constructor ignored}} + // expected-note@-3 {{explicit constructor declared here}} + template + explicit(enable_ifv::value, a>::value) + //expected-note@-1 {{explicit(bool) specifier resolved to true}} + A(T) {} + // expected-note@-1+ {{substitution failure}} + // expected-note@-2 {{candidate constructor ignored}} + // expected-note@-3 {{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}; + +A d0 = true; // expected-error {{no viable conversion}} +A d1( true); +A d4{ true}; +A d7 = { true}; // expected-error {{chosen constructor is explicit}} + +} + +namespace conversion { + +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 conversion2 { + +struct B {}; +// expected-note@-1+ {{candidate constructor}} +template +struct A { + template + explicit(enable_ifv::value, a>::value) + // expected-note@-1+ {{explicit(bool) specifier resolved to true}} + operator T2() { return T2(); }; + // expected-note@-1+ {{substitution failure}} + // expected-note@-2+ {{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 parameter_pack { + +template +struct A { + // expected-note@-1+ {{candidate constructor}} + // expected-note@-2+ {{candidate function}} + 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 ...) {} + +void f() { + +A a0 = 0; // expected-error {{no viable conversion}} +A a1( 0, 1); +A a2{ 0, 1}; +A 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 b0 = 0; +A b1( 0, 1); +A b2{ 0, 1}; +A b3 = { 0, 1}; + +b1 = 0; +b2 = { 0, 1}; + +} + +} + +namespace deduction_guide { + +template +struct B {}; + +B b_true; +B b_false; + +template +struct nondeduced +{ +using type = T; +}; + +template +struct A { + // expected-note@-1+ {{candidate function}} + explicit(false) + A(typename nondeduced::type, typename nondeduced::type, typename nondeduced>::type) {} + // expected-note@-1+ {{candidate template ignored}} +}; + +template +explicit(enable_ifv::value, b>::value) +A(T1, T2, B) -> A; +// expected-note@-1+ {{explicit deduction guide declared here}} +// expected-note@-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 +struct A { + //expected-note@-1+ {{candidate function}} + template + explicit(b) + A(T1, T2) {} + //expected-note@-1 {{explicit constructor declared here}} +}; + +template +explicit(!is_same::value) +A(T1, T2) -> A::value>; +// expected-note@-1+ {{explicit deduction guide declared here}} + +template +A 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()); +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()); +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 +struct A { + explicit(!b) operator int(); + explicit(b) operator bool(); +}; + +template +A::operator bool() { return false; } + +struct B { + void f(int); + void f(bool); +}; + +void f(A a, B b) { + b.f(a); +} + +void f1(A a, B b) { + b.f(a); +} + +// Taken from 12.3.2p2 +class X { X(); }; +class Y { }; // expected-note+ {{candidate constructor (the implicit}} + +template +struct Z { + explicit(b) operator X() const; + explicit(b) operator Y() const; + explicit(b) operator int() const; +}; + +void testExplicit() +{ +Z 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(z); +// 13.3.1.5p1 & 8.5p16: +int i1 = (int)z; +int i2 = int(z); +int i3 = static_cast(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 +struct C { + template + explicit(!is_same::value) + // expected-note@-1+ {{explicit(bool) specifier resolved to true}} + operator T(); + // expected-note@-1+ {{candidate conversion operator ignored}} +}; + +using Bool = C; +using Integral = C; +using Unrelated = C; + +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 ©5 = b; +const bool ©6 = n;// expected-error {{no viable conversion}} +const bool ©u6 = u;// expected-error {{no viable conversion}} +const int ©7 = b;// expected-error {{no viable conversion}} +const int ©8 = n; +const int ©u8 = 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 ©List5 = {b}; +const bool ©List6 = {n};// expected-error {{no viable conversion}} +const bool ©Listu6 = {u};// expected-error {{no viable conversion}} +const int ©List7 = {b};// expected-error {{no viable conversion}} +const int ©List8 = {n}; +const int ©Listu8 = {u};// expected-error {{no viable conversion}} +} + +} + +namespace deduction_guide2 { + +template +struct A { + // expected-note@-1+ {{candidate template ignored}} + explicit(!is_same::value) + // expected-note@-1+ {{explicit(bool) specifier resolved to true}} + A(T1 = 0, T2 = 0) {} + // expected-note@-1 {{explicit constructor}} + // expected-note@-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 +explicit A(T1, T2) -> A; +// expected-note@-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}} + +} Index: cfe/trunk/test/SemaCXX/explicit.cpp =================================================================== --- cfe/trunk/test/SemaCXX/explicit.cpp +++ cfe/trunk/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); @@ -34,6 +36,21 @@ B b4{0}; B &&b5 = {0}; // expected-error {{chosen constructor is explicit}} B &&b6{0}; + +struct S { + template + explicit S(); +}; + +struct T : S { + // T(); +}; + +struct U : T { + U(); +}; +U::U() {} + } namespace Conversion { @@ -183,7 +200,8 @@ const int ©List7 = {b}; const int ©List8 = {n}; // expected-error {{no viable conversion}} } - + +#if __cplusplus < 201707L void testNew() { // 5.3.4p6: @@ -200,7 +218,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: cfe/trunk/unittests/AST/Language.h =================================================================== --- cfe/trunk/unittests/AST/Language.h +++ cfe/trunk/unittests/AST/Language.h @@ -28,6 +28,7 @@ Lang_CXX, Lang_CXX11, Lang_CXX14, + Lang_CXX2a, Lang_OpenCL, Lang_OBJCXX }; Index: cfe/trunk/unittests/AST/Language.cpp =================================================================== --- cfe/trunk/unittests/AST/Language.cpp +++ cfe/trunk/unittests/AST/Language.cpp @@ -34,6 +34,9 @@ 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!"); Index: cfe/trunk/unittests/AST/MatchVerifier.h =================================================================== --- cfe/trunk/unittests/AST/MatchVerifier.h +++ cfe/trunk/unittests/AST/MatchVerifier.h @@ -108,6 +108,10 @@ 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; Index: cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp =================================================================== --- cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp +++ cfe/trunk/unittests/AST/StructuralEquivalenceTest.cpp @@ -806,6 +806,26 @@ 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().match( + get<0>(Decls), cxxConstructorDecl(hasName("foo"))); + CXXConstructorDecl *Second = FirstDeclMatcher().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().match( + get<0>(Decls), cxxConstructorDecl(hasName("foo"))); + CXXConstructorDecl *Second = FirstDeclMatcher().match( + get<1>(Decls), cxxConstructorDecl(hasName("foo"))); + EXPECT_TRUE(testStructuralMatch(First, Second)); +} + struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {}; TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) { @@ -853,5 +873,25 @@ EXPECT_FALSE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) { + auto Decls = makeNamedDecls("template struct foo {explicit(b) foo(int);};", + "template struct foo {explicit(b) foo(int);};", Lang_CXX2a); + CXXConstructorDecl *First = FirstDeclMatcher().match( + get<0>(Decls), cxxConstructorDecl(hasName("foo"))); + CXXConstructorDecl *Second = FirstDeclMatcher().match( + get<1>(Decls), cxxConstructorDecl(hasName("foo"))); + EXPECT_TRUE(testStructuralMatch(First, Second)); +} + +TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) { + auto Decls = makeNamedDecls("template struct foo {explicit(b) foo(int);};", + "template struct foo {explicit(!b) foo(int);};", Lang_CXX2a); + CXXConstructorDecl *First = FirstDeclMatcher().match( + get<0>(Decls), cxxConstructorDecl(hasName("foo"))); + CXXConstructorDecl *Second = FirstDeclMatcher().match( + get<1>(Decls), cxxConstructorDecl(hasName("foo"))); + EXPECT_FALSE(testStructuralMatch(First, Second)); +} + } // end namespace ast_matchers } // end namespace clang Index: cfe/trunk/www/cxx_status.html =================================================================== --- cfe/trunk/www/cxx_status.html +++ cfe/trunk/www/cxx_status.html @@ -1002,7 +1002,7 @@ explicit(bool) P0892R2 - No + SVN