diff options
author | Nicolas Lesser <blitzrakete@gmail.com> | 2019-05-04 00:09:00 +0000 |
---|---|---|
committer | Nicolas Lesser <blitzrakete@gmail.com> | 2019-05-04 00:09:00 +0000 |
commit | 6de0b449c07ec7adbcb34e7c94c544ee37ef5963 (patch) | |
tree | 0e2112dbbe57b79622f5a7708add8fecc6a75b80 /include | |
parent | 6cc60c9164a96f1d73ccfd302303490e0d085b87 (diff) |
[clang] adding explicit(bool) from c++2a
this patch adds support for the explicit bool specifier.
Changes:
- The parsing for the explicit(bool) specifier was added in ParseDecl.cpp.
- The storage of the explicit specifier was changed. the explicit specifier was stored as a boolean value in the FunctionDeclBitfields and in the DeclSpec class. now it is stored as a PointerIntPair<Expr*, 2> with a flag and a potential expression in CXXConstructorDecl, CXXDeductionGuideDecl, CXXConversionDecl and in the DeclSpec class.
- Following the AST change, Serialization, ASTMatchers, ASTComparator and ASTPrinter were adapted.
- Template instantiation was adapted to instantiate the potential expressions of the explicit(bool) specifier When instantiating their associated declaration.
- The Add*Candidate functions were adapted, they now take a Boolean indicating if the context allowing explicit constructor or conversion function and this boolean is used to remove invalid overloads that required template instantiation to be detected.
- Test for Semantic and Serialization were added.
This patch is not yet complete. I still need to check that interaction with CTAD and deduction guides is correct. and add more tests for AST operations. But I wanted first feedback.
Perhaps this patch should be spited in smaller patches, but making each patch testable as a standalone may be tricky.
Patch by Tyker
Differential Revision: https://reviews.llvm.org/D60934
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@359949 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'include')
-rw-r--r-- | include/clang/AST/Decl.h | 10 | ||||
-rw-r--r-- | include/clang/AST/DeclBase.h | 20 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 176 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticCommonKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.td | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 13 | ||||
-rw-r--r-- | include/clang/Basic/Specifiers.h | 8 | ||||
-rw-r--r-- | include/clang/Sema/DeclSpec.h | 62 | ||||
-rw-r--r-- | include/clang/Sema/Overload.h | 5 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 38 | ||||
-rw-r--r-- | include/clang/Serialization/ASTBitCodes.h | 3 | ||||
-rw-r--r-- | include/clang/Serialization/ASTReader.h | 8 |
13 files changed, 241 insertions, 111 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index da8128937e..cfb9ff8948 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2369,16 +2369,6 @@ public: /// that was defined in the class body. bool isInlined() const { return FunctionDeclBits.IsInline; } - /// Whether this function is marked as explicit explicitly. - bool isExplicitSpecified() const { - return FunctionDeclBits.IsExplicitSpecified; - } - - /// State that this function is marked as explicit explicitly. - void setExplicitSpecified(bool ExpSpec = true) { - FunctionDeclBits.IsExplicitSpecified = ExpSpec; - } - bool isInlineDefinitionExternallyVisible() const; bool isMSExternInline() const; diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 64adf304c6..ad283a6bc1 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -1472,10 +1472,6 @@ class DeclContext { uint64_t IsInline : 1; uint64_t IsInlineSpecified : 1; - /// This is shared by CXXConstructorDecl, - /// CXXConversionDecl, and CXXDeductionGuideDecl. - uint64_t IsExplicitSpecified : 1; - uint64_t IsVirtualAsWritten : 1; uint64_t IsPure : 1; uint64_t HasInheritedPrototype : 1; @@ -1523,7 +1519,7 @@ class DeclContext { }; /// Number of non-inherited bits in FunctionDeclBitfields. - enum { NumFunctionDeclBits = 25 }; + enum { NumFunctionDeclBits = 24 }; /// Stores the bits used by CXXConstructorDecl. If modified /// NumCXXConstructorDeclBits and the accessor @@ -1535,17 +1531,25 @@ class DeclContext { /// For the bits in FunctionDeclBitfields. uint64_t : NumFunctionDeclBits; - /// 25 bits to fit in the remaining availible space. + /// 24 bits to fit in the remaining available space. /// Note that this makes CXXConstructorDeclBitfields take /// exactly 64 bits and thus the width of NumCtorInitializers /// will need to be shrunk if some bit is added to NumDeclContextBitfields, /// NumFunctionDeclBitfields or CXXConstructorDeclBitfields. - uint64_t NumCtorInitializers : 25; + uint64_t NumCtorInitializers : 24; uint64_t IsInheritingConstructor : 1; + + /// Whether this constructor has a trail-allocated explicit specifier. + uint64_t HasTrailingExplicitSpecifier : 1; + /// If this constructor does't have a trail-allocated explicit specifier. + /// Whether this constructor is explicit specified. + uint64_t IsSimpleExplicit : 1; }; /// Number of non-inherited bits in CXXConstructorDeclBitfields. - enum { NumCXXConstructorDeclBits = 26 }; + enum { + NumCXXConstructorDeclBits = 64 - NumDeclContextBits - NumFunctionDeclBits + }; /// Stores the bits used by ObjCMethodDecl. /// If modified NumObjCMethodDeclBits and the accessor diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index a1717e6273..5a9e418a2c 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1990,6 +1990,50 @@ public: } }; +/// Store information needed for an explicit specifier. +/// used by CXXDeductionGuideDecl, CXXConstructorDecl and CXXConversionDecl. +class ExplicitSpecifier { + llvm::PointerIntPair<Expr *, 2, ExplicitSpecKind> ExplicitSpec{ + nullptr, ExplicitSpecKind::ResolvedFalse}; + +public: + ExplicitSpecifier() = default; + ExplicitSpecifier(Expr *Expression, ExplicitSpecKind Kind) + : ExplicitSpec(Expression, Kind) {} + ExplicitSpecKind getKind() const { return ExplicitSpec.getInt(); } + const Expr *getExpr() const { return ExplicitSpec.getPointer(); } + Expr *getExpr() { return ExplicitSpec.getPointer(); } + + /// Return true if the ExplicitSpecifier isn't defaulted. + bool isSpecified() const { + return ExplicitSpec.getInt() != ExplicitSpecKind::ResolvedFalse || + ExplicitSpec.getPointer(); + } + + /// Check for Equivalence of explicit specifiers. + /// Return True if the explicit specifier are equivalent false otherwise. + bool isEquivalent(const ExplicitSpecifier Other) const; + /// Return true if the explicit specifier is already resolved to be explicit. + bool isExplicit() const { + return ExplicitSpec.getInt() == ExplicitSpecKind::ResolvedTrue; + } + /// Return true if the ExplicitSpecifier isn't valid. + /// This state occurs after a substitution failures. + bool isInvalid() const { + return ExplicitSpec.getInt() == ExplicitSpecKind::Unresolved && + !ExplicitSpec.getPointer(); + } + void setKind(ExplicitSpecKind Kind) { ExplicitSpec.setInt(Kind); } + void setExpr(Expr *E) { ExplicitSpec.setPointer(E); } + // getFromDecl - retrieve the explicit specifier in the given declaration. + // if the given declaration has no explicit. the returned explicit specifier + // is defaulted. .isSpecified() will be false. + static ExplicitSpecifier getFromDecl(FunctionDecl *Function); + static ExplicitSpecifier Invalid() { + return ExplicitSpecifier(nullptr, ExplicitSpecKind::Unresolved); + } +}; + /// Represents a C++ deduction guide declaration. /// /// \code @@ -2005,31 +2049,36 @@ class CXXDeductionGuideDecl : public FunctionDecl { 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 { @@ -2498,7 +2547,8 @@ public: /// \endcode class CXXConstructorDecl final : public CXXMethodDecl, - private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor> { + private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor, + ExplicitSpecifier> { // This class stores some data in DeclContext::CXXConstructorDeclBits // to save some space. Use the provided accessors to access it. @@ -2508,28 +2558,74 @@ class CXXConstructorDecl final LazyCXXCtorInitializersPtr CtorInitializers; CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isExplicitSpecified, bool isInline, + const DeclarationNameInfo &NameInfo, QualType T, + TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, bool isConstexpr, InheritedConstructor Inherited); void anchor() override; + size_t numTrailingObjects(OverloadToken<InheritedConstructor>) const { + return CXXConstructorDeclBits.IsInheritingConstructor; + } + size_t numTrailingObjects(OverloadToken<ExplicitSpecifier>) const { + return CXXConstructorDeclBits.HasTrailingExplicitSpecifier; + } + + ExplicitSpecifier getExplicitSpecifierInternal() const { + if (CXXConstructorDeclBits.HasTrailingExplicitSpecifier) + return *getCanonicalDecl()->getTrailingObjects<ExplicitSpecifier>(); + return ExplicitSpecifier( + nullptr, getCanonicalDecl()->CXXConstructorDeclBits.IsSimpleExplicit + ? ExplicitSpecKind::ResolvedTrue + : ExplicitSpecKind::ResolvedFalse); + } + + void setExplicitSpecifier(ExplicitSpecifier ES) { + assert((!ES.getExpr() || + CXXConstructorDeclBits.HasTrailingExplicitSpecifier) && + "cannot set this explicit specifier. no trail-allocated space for " + "explicit"); + if (ES.getExpr()) + *getCanonicalDecl()->getTrailingObjects<ExplicitSpecifier>() = ES; + else + CXXConstructorDeclBits.IsSimpleExplicit = ES.isExplicit(); + } + + enum TraillingAllocKind { + TAKInheritsConstructor = 1, + TAKHasTailExplicit = 1 << 1, + }; + + uint64_t getTraillingAllocKind() const { + return numTrailingObjects(OverloadToken<InheritedConstructor>()) | + (numTrailingObjects(OverloadToken<ExplicitSpecifier>()) << 1); + } + public: friend class ASTDeclReader; friend class ASTDeclWriter; friend TrailingObjects; static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID, - bool InheritsConstructor); + uint64_t AllocKind); static CXXConstructorDecl * Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isExplicit, bool isInline, bool isImplicitlyDeclared, + ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, bool isConstexpr, InheritedConstructor Inherited = InheritedConstructor()); + ExplicitSpecifier getExplicitSpecifier() { + return getExplicitSpecifierInternal(); + } + const ExplicitSpecifier getExplicitSpecifier() const { + return getExplicitSpecifierInternal(); + } + + /// Return true if the declartion is already resolved to be explicit. + bool isExplicit() const { return getExplicitSpecifier().isExplicit(); } + /// Iterates through the member/base initializer list. using init_iterator = CXXCtorInitializer **; @@ -2600,11 +2696,6 @@ public: CtorInitializers = Initializers; } - /// Whether this function is explicit. - bool isExplicit() const { - return getCanonicalDecl()->isExplicitSpecified(); - } - /// Determine whether this constructor is a delegating constructor. bool isDelegatingConstructor() const { return (getNumCtorInitializers() == 1) && @@ -2783,34 +2874,39 @@ public: class CXXConversionDecl : public CXXMethodDecl { CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, - TypeSourceInfo *TInfo, bool isInline, - bool isExplicitSpecified, bool isConstexpr, - SourceLocation EndLocation) + TypeSourceInfo *TInfo, bool isInline, ExplicitSpecifier ES, + bool isConstexpr, SourceLocation EndLocation) : CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, isConstexpr, EndLocation) { - setExplicitSpecified(isExplicitSpecified); - } - + SC_None, isInline, isConstexpr, EndLocation), + ExplicitSpec(ES) {} void anchor() override; + ExplicitSpecifier ExplicitSpec; + + void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; } + public: friend class ASTDeclReader; friend class ASTDeclWriter; - static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD, - SourceLocation StartLoc, - const DeclarationNameInfo &NameInfo, - QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isExplicit, - bool isConstexpr, - SourceLocation EndLocation); + static CXXConversionDecl * + Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, + bool isInline, ExplicitSpecifier ES, bool isConstexpr, + SourceLocation EndLocation); static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID); - /// Whether this function is explicit. - bool isExplicit() const { - return getCanonicalDecl()->isExplicitSpecified(); + ExplicitSpecifier getExplicitSpecifier() { + return getCanonicalDecl()->ExplicitSpec; } + const ExplicitSpecifier getExplicitSpecifier() const { + return getCanonicalDecl()->ExplicitSpec; + } + + /// Return true if the declartion is already resolved to be explicit. + bool isExplicit() const { return getExplicitSpecifier().isExplicit(); } + /// Returns the type that this conversion function is converting to. QualType getConversionType() const { return getType()->getAs<FunctionType>()->getReturnType(); diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h index 8bd4429f0b..57dff7993d 100644 --- a/include/clang/ASTMatchers/ASTMatchers.h +++ b/include/clang/ASTMatchers/ASTMatchers.h @@ -6171,6 +6171,9 @@ AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) { 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(); } diff --git a/include/clang/Basic/DiagnosticCommonKinds.td b/include/clang/Basic/DiagnosticCommonKinds.td index 7cd3b21109..0727980751 100644 --- a/include/clang/Basic/DiagnosticCommonKinds.td +++ b/include/clang/Basic/DiagnosticCommonKinds.td @@ -150,6 +150,8 @@ def ext_warn_duplicate_declspec : ExtWarn<"%sub{duplicate_declspec}0">, def warn_duplicate_declspec : Warning<"%sub{duplicate_declspec}0">, InGroup<DuplicateDeclSpecifier>; +def err_duplicate_declspec : Error<"%sub{duplicate_declspec}0">; + def err_friend_decl_spec : Error<"'%0' is invalid in friend declarations">; def err_invalid_member_in_interface : Error< diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 4bd29b629d..8b9d6cdd7a 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -33,6 +33,10 @@ def err_asm_goto_not_supported_yet : Error< let CategoryName = "Parse Issue" in { +def warn_cxx2a_compat_explicit_bool : Warning< + "this expression will be parsed as explicit(bool) in C++2a">, + InGroup<CXX2aCompat>, DefaultIgnore; + def ext_empty_translation_unit : Extension< "ISO C requires a translation unit to contain at least one declaration">, InGroup<DiagGroup<"empty-translation-unit">>; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index cccc9e4aa0..84145c1d32 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -83,11 +83,11 @@ def err_typecheck_converted_constant_expression_indirect : Error< "bind reference to a temporary">; def err_expr_not_cce : Error< "%select{case value|enumerator value|non-type template argument|" - "array size|constexpr if condition}0 " + "array size|constexpr if condition|explicit specifier argument}0 " "is not a constant expression">; def ext_cce_narrowing : ExtWarn< "%select{case value|enumerator value|non-type template argument|" - "array size|constexpr if condition}0 " + "array size|constexpr if condition|explicit specifier argument}0 " "%select{cannot be narrowed from type %2 to %3|" "evaluates to %2, which cannot be narrowed to type %3}1">, InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure; @@ -2115,9 +2115,8 @@ def err_deduction_guide_wrong_scope : Error< "deduction guide must be declared in the same scope as template %q0">; def err_deduction_guide_defines_function : Error< "deduction guide cannot have a function definition">; -def err_deduction_guide_explicit_mismatch : Error< - "deduction guide is %select{not |}0declared 'explicit' but " - "previous declaration was%select{ not|}0">; +def err_deduction_guide_redeclared : Error< + "redeclaration of deduction guide">; def err_deduction_guide_specialized : Error<"deduction guide cannot be " "%select{explicitly instantiated|explicitly specialized}0">; def err_deduction_guide_template_not_deducible : Error< @@ -3640,6 +3639,10 @@ def note_ovl_candidate : Note< "| has different qualifiers (expected %5 but found %6)" "| has different exception specification}4">; +def note_ovl_candidate_explicit_forbidden : Note< + "candidate %0 ignored: cannot be explicit">; +def note_explicit_bool_resolved_to_true : Note< + "explicit(bool) specifier resolved to true">; def note_ovl_candidate_inherited_constructor : Note< "constructor from base class %0 inherited here">; def note_ovl_candidate_inherited_constructor_slice : Note< diff --git a/include/clang/Basic/Specifiers.h b/include/clang/Basic/Specifiers.h index 7256acafde..cc0c1c82df 100644 --- a/include/clang/Basic/Specifiers.h +++ b/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, diff --git a/include/clang/Sema/DeclSpec.h b/include/clang/Sema/DeclSpec.h index babdc9d8f7..f1c2a67400 100644 --- a/include/clang/Sema/DeclSpec.h +++ b/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 @@ private: unsigned FS_inline_specified : 1; unsigned FS_forceinline_specified: 1; unsigned FS_virtual_specified : 1; - unsigned FS_explicit_specified : 1; unsigned FS_noreturn_specified : 1; // friend-specifier @@ -371,6 +371,9 @@ private: Expr *ExprRep; }; + /// ExplicitSpecifier - Store information about explicit spicifer. + ExplicitSpecifier FS_explicit_specifier; + // attributes. ParsedAttributes Attrs; @@ -393,6 +396,7 @@ private: SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc; SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc; + SourceLocation FS_explicitCloseParenLoc; SourceLocation FS_forceinlineLoc; SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc; SourceLocation TQ_pipeLoc; @@ -420,31 +424,18 @@ public: } DeclSpec(AttributeFactory &attrFactory) - : StorageClassSpec(SCS_unspecified), - ThreadStorageClassSpec(TSCS_unspecified), - SCS_extern_in_linkage_spec(false), - TypeSpecWidth(TSW_unspecified), - TypeSpecComplex(TSC_unspecified), - TypeSpecSign(TSS_unspecified), - TypeSpecType(TST_unspecified), - TypeAltiVecVector(false), - TypeAltiVecPixel(false), - TypeAltiVecBool(false), - TypeSpecOwned(false), - TypeSpecPipe(false), - TypeSpecSat(false), - TypeQualifiers(TQ_unspecified), - FS_inline_specified(false), - FS_forceinline_specified(false), - FS_virtual_specified(false), - FS_explicit_specified(false), - FS_noreturn_specified(false), - Friend_specified(false), - Constexpr_specified(false), - Attrs(attrFactory), - writtenBS(), - ObjCQualifiers(nullptr) { - } + : StorageClassSpec(SCS_unspecified), + ThreadStorageClassSpec(TSCS_unspecified), + SCS_extern_in_linkage_spec(false), TypeSpecWidth(TSW_unspecified), + TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified), + TypeSpecType(TST_unspecified), TypeAltiVecVector(false), + TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false), + TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified), + FS_inline_specified(false), FS_forceinline_specified(false), + FS_virtual_specified(false), FS_noreturn_specified(false), + Friend_specified(false), Constexpr_specified(false), + FS_explicit_specifier(), Attrs(attrFactory), writtenBS(), + ObjCQualifiers(nullptr) {} // storage-class-specifier SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; } @@ -570,11 +561,22 @@ public: return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc; } + ExplicitSpecifier getExplicitSpecifier() const { + return FS_explicit_specifier; + } + bool isVirtualSpecified() const { return FS_virtual_specified; } SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; } - bool isExplicitSpecified() const { return FS_explicit_specified; } + bool hasExplicitSpecifier() const { + return FS_explicit_specifier.isSpecified(); + } SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; } + SourceRange getExplicitSpecRange() const { + return FS_explicit_specifier.getExpr() + ? SourceRange(FS_explicitLoc, FS_explicitCloseParenLoc) + : SourceRange(FS_explicitLoc); + } bool isNoreturnSpecified() const { return FS_noreturn_specified; } SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; } @@ -586,8 +588,9 @@ public: FS_forceinlineLoc = SourceLocation(); FS_virtual_specified = false; FS_virtualLoc = SourceLocation(); - FS_explicit_specified = false; + FS_explicit_specifier = ExplicitSpecifier(); FS_explicitLoc = SourceLocation(); + FS_explicitCloseParenLoc = SourceLocation(); FS_noreturn_specified = false; FS_noreturnLoc = SourceLocation(); } @@ -706,7 +709,8 @@ public: bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID); + unsigned &DiagID, ExplicitSpecifier ExplicitSpec, + SourceLocation CloseParenLoc); bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID); diff --git a/include/clang/Sema/Overload.h b/include/clang/Sema/Overload.h index 342ce0f026..cacb592b18 100644 --- a/include/clang/Sema/Overload.h +++ b/include/clang/Sema/Overload.h @@ -705,6 +705,11 @@ class Sema; /// attribute disabled it. ovl_fail_enable_if, + /// This candidate constructor or conversion fonction + /// is used implicitly but the explicit(bool) specifier + /// was resolved to true + ovl_fail_explicit_resolved, + /// This candidate was not viable because its address could not be taken. ovl_fail_addr_not_available, diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 93932b4ff6..91a0cfd317 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2744,7 +2744,8 @@ public: CCEK_Enumerator, ///< Enumerator value with fixed underlying type. CCEK_TemplateArg, ///< Value of a non-type template parameter. CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator. - CCEK_ConstexprIf ///< Condition in a constexpr if statement. + CCEK_ConstexprIf, ///< Condition in a constexpr if statement. + CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier. }; ExprResult CheckConvertedConstantExpression(Expr *From, QualType T, llvm::APSInt &Value, CCEKind CCE); @@ -2867,6 +2868,7 @@ public: bool SuppressUserConversions = false, bool PartialOverloading = false, bool AllowExplicit = false, + bool AllowExplicitConversion = false, ADLCallKind IsADLCandidate = ADLCallKind::NotADL, ConversionSequenceList EarlyConversions = None); void AddFunctionCandidates(const UnresolvedSetImpl &Functions, @@ -2905,7 +2907,7 @@ public: FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, - bool PartialOverloading = false, + bool PartialOverloading = false, bool AllowExplicit = false, ADLCallKind IsADLCandidate = ADLCallKind::NotADL); bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes, @@ -2917,20 +2919,16 @@ public: QualType ObjectType = QualType(), Expr::Classification ObjectClassification = {}); - void AddConversionCandidate(CXXConversionDecl *Conversion, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - Expr *From, QualType ToType, - OverloadCandidateSet& CandidateSet, - bool AllowObjCConversionOnExplicit, - bool AllowResultConversion = true); - void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, - Expr *From, QualType ToType, - OverloadCandidateSet &CandidateSet, - bool AllowObjCConversionOnExplicit, - bool AllowResultConversion = true); + void AddConversionCandidate( + CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, + bool AllowExplicit, bool AllowResultConversion = true); + void AddTemplateConversionCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, + bool AllowExplicit, bool AllowResultConversion = true); void AddSurrogateCandidate(CXXConversionDecl *Conversion, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, @@ -10120,6 +10118,14 @@ public: ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E, bool IsConstexpr = false); + /// ActOnExplicitBoolSpecifier - Build an ExplicitSpecifier from an expression + /// found in an explicit(bool) specifier. + ExplicitSpecifier ActOnExplicitBoolSpecifier(Expr *E); + + /// tryResolveExplicitSpecifier - Attempt to resolve the explict specifier. + /// Returns true if the explicit specifier is now resolved. + bool tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec); + /// DiagnoseAssignmentAsCondition - Given that an expression is /// being used as a boolean condition, warn if it's an assignment. void DiagnoseAssignmentAsCondition(Expr *E); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 0365e3a696..b38b6b034d 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1438,9 +1438,6 @@ namespace serialization { /// A CXXConstructorDecl record. DECL_CXX_CONSTRUCTOR, - /// A CXXConstructorDecl record for an inherited constructor. - DECL_CXX_INHERITED_CONSTRUCTOR, - /// A CXXDestructorDecl record. DECL_CXX_DESTRUCTOR, diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 423313ea56..579cdc1bff 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -2430,6 +2430,14 @@ public: ID); } + ExplicitSpecifier readExplicitSpec() { + uint64_t Kind = readInt(); + bool HasExpr = Kind & 0x1; + Kind = Kind >> 1; + return ExplicitSpecifier(HasExpr ? readExpr() : nullptr, + static_cast<ExplicitSpecKind>(Kind)); + } + void readExceptionSpec(SmallVectorImpl<QualType> &ExceptionStorage, FunctionProtoType::ExceptionSpecInfo &ESI) { return Reader->readExceptionSpec(*F, ExceptionStorage, ESI, Record, Idx); |