forked from OSchip/llvm-project
[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 llvm-svn: 359949
This commit is contained in:
parent
a6b41d7c52
commit
5fe2ddbdf4
|
@ -2369,16 +2369,6 @@ public:
|
||||||
/// that was defined in the class body.
|
/// that was defined in the class body.
|
||||||
bool isInlined() const { return FunctionDeclBits.IsInline; }
|
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 isInlineDefinitionExternallyVisible() const;
|
||||||
|
|
||||||
bool isMSExternInline() const;
|
bool isMSExternInline() const;
|
||||||
|
|
|
@ -1472,10 +1472,6 @@ class DeclContext {
|
||||||
uint64_t IsInline : 1;
|
uint64_t IsInline : 1;
|
||||||
uint64_t IsInlineSpecified : 1;
|
uint64_t IsInlineSpecified : 1;
|
||||||
|
|
||||||
/// This is shared by CXXConstructorDecl,
|
|
||||||
/// CXXConversionDecl, and CXXDeductionGuideDecl.
|
|
||||||
uint64_t IsExplicitSpecified : 1;
|
|
||||||
|
|
||||||
uint64_t IsVirtualAsWritten : 1;
|
uint64_t IsVirtualAsWritten : 1;
|
||||||
uint64_t IsPure : 1;
|
uint64_t IsPure : 1;
|
||||||
uint64_t HasInheritedPrototype : 1;
|
uint64_t HasInheritedPrototype : 1;
|
||||||
|
@ -1523,7 +1519,7 @@ class DeclContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Number of non-inherited bits in FunctionDeclBitfields.
|
/// Number of non-inherited bits in FunctionDeclBitfields.
|
||||||
enum { NumFunctionDeclBits = 25 };
|
enum { NumFunctionDeclBits = 24 };
|
||||||
|
|
||||||
/// Stores the bits used by CXXConstructorDecl. If modified
|
/// Stores the bits used by CXXConstructorDecl. If modified
|
||||||
/// NumCXXConstructorDeclBits and the accessor
|
/// NumCXXConstructorDeclBits and the accessor
|
||||||
|
@ -1535,17 +1531,25 @@ class DeclContext {
|
||||||
/// For the bits in FunctionDeclBitfields.
|
/// For the bits in FunctionDeclBitfields.
|
||||||
uint64_t : NumFunctionDeclBits;
|
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
|
/// Note that this makes CXXConstructorDeclBitfields take
|
||||||
/// exactly 64 bits and thus the width of NumCtorInitializers
|
/// exactly 64 bits and thus the width of NumCtorInitializers
|
||||||
/// will need to be shrunk if some bit is added to NumDeclContextBitfields,
|
/// will need to be shrunk if some bit is added to NumDeclContextBitfields,
|
||||||
/// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
|
/// NumFunctionDeclBitfields or CXXConstructorDeclBitfields.
|
||||||
uint64_t NumCtorInitializers : 25;
|
uint64_t NumCtorInitializers : 24;
|
||||||
uint64_t IsInheritingConstructor : 1;
|
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.
|
/// Number of non-inherited bits in CXXConstructorDeclBitfields.
|
||||||
enum { NumCXXConstructorDeclBits = 26 };
|
enum {
|
||||||
|
NumCXXConstructorDeclBits = 64 - NumDeclContextBits - NumFunctionDeclBits
|
||||||
|
};
|
||||||
|
|
||||||
/// Stores the bits used by ObjCMethodDecl.
|
/// Stores the bits used by ObjCMethodDecl.
|
||||||
/// If modified NumObjCMethodDeclBits and the accessor
|
/// If modified NumObjCMethodDeclBits and the accessor
|
||||||
|
|
|
@ -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.
|
/// Represents a C++ deduction guide declaration.
|
||||||
///
|
///
|
||||||
/// \code
|
/// \code
|
||||||
|
@ -2005,31 +2049,36 @@ class CXXDeductionGuideDecl : public FunctionDecl {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
|
CXXDeductionGuideDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
|
||||||
bool IsExplicit, const DeclarationNameInfo &NameInfo,
|
ExplicitSpecifier ES,
|
||||||
QualType T, TypeSourceInfo *TInfo,
|
const DeclarationNameInfo &NameInfo, QualType T,
|
||||||
SourceLocation EndLocation)
|
TypeSourceInfo *TInfo, SourceLocation EndLocation)
|
||||||
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
|
: FunctionDecl(CXXDeductionGuide, C, DC, StartLoc, NameInfo, T, TInfo,
|
||||||
SC_None, false, false) {
|
SC_None, false, false),
|
||||||
|
ExplicitSpec(ES) {
|
||||||
if (EndLocation.isValid())
|
if (EndLocation.isValid())
|
||||||
setRangeEnd(EndLocation);
|
setRangeEnd(EndLocation);
|
||||||
setExplicitSpecified(IsExplicit);
|
|
||||||
setIsCopyDeductionCandidate(false);
|
setIsCopyDeductionCandidate(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExplicitSpecifier ExplicitSpec;
|
||||||
|
void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
friend class ASTDeclWriter;
|
friend class ASTDeclWriter;
|
||||||
|
|
||||||
static CXXDeductionGuideDecl *Create(ASTContext &C, DeclContext *DC,
|
static CXXDeductionGuideDecl *
|
||||||
SourceLocation StartLoc, bool IsExplicit,
|
Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
|
||||||
const DeclarationNameInfo &NameInfo,
|
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
|
||||||
QualType T, TypeSourceInfo *TInfo,
|
TypeSourceInfo *TInfo, SourceLocation EndLocation);
|
||||||
SourceLocation EndLocation);
|
|
||||||
|
|
||||||
static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||||
|
|
||||||
/// Whether this deduction guide is explicit.
|
ExplicitSpecifier getExplicitSpecifier() { return ExplicitSpec; }
|
||||||
bool isExplicit() const { return isExplicitSpecified(); }
|
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.
|
/// Get the template for which this guide performs deduction.
|
||||||
TemplateDecl *getDeducedTemplate() const {
|
TemplateDecl *getDeducedTemplate() const {
|
||||||
|
@ -2498,7 +2547,8 @@ public:
|
||||||
/// \endcode
|
/// \endcode
|
||||||
class CXXConstructorDecl final
|
class CXXConstructorDecl final
|
||||||
: public CXXMethodDecl,
|
: public CXXMethodDecl,
|
||||||
private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor> {
|
private llvm::TrailingObjects<CXXConstructorDecl, InheritedConstructor,
|
||||||
|
ExplicitSpecifier> {
|
||||||
// This class stores some data in DeclContext::CXXConstructorDeclBits
|
// This class stores some data in DeclContext::CXXConstructorDeclBits
|
||||||
// to save some space. Use the provided accessors to access it.
|
// to save some space. Use the provided accessors to access it.
|
||||||
|
|
||||||
|
@ -2508,28 +2558,74 @@ class CXXConstructorDecl final
|
||||||
LazyCXXCtorInitializersPtr CtorInitializers;
|
LazyCXXCtorInitializersPtr CtorInitializers;
|
||||||
|
|
||||||
CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
CXXConstructorDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||||
const DeclarationNameInfo &NameInfo,
|
const DeclarationNameInfo &NameInfo, QualType T,
|
||||||
QualType T, TypeSourceInfo *TInfo,
|
TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool isInline,
|
||||||
bool isExplicitSpecified, bool isInline,
|
|
||||||
bool isImplicitlyDeclared, bool isConstexpr,
|
bool isImplicitlyDeclared, bool isConstexpr,
|
||||||
InheritedConstructor Inherited);
|
InheritedConstructor Inherited);
|
||||||
|
|
||||||
void anchor() override;
|
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:
|
public:
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
friend class ASTDeclWriter;
|
friend class ASTDeclWriter;
|
||||||
friend TrailingObjects;
|
friend TrailingObjects;
|
||||||
|
|
||||||
static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID,
|
static CXXConstructorDecl *CreateDeserialized(ASTContext &C, unsigned ID,
|
||||||
bool InheritsConstructor);
|
uint64_t AllocKind);
|
||||||
static CXXConstructorDecl *
|
static CXXConstructorDecl *
|
||||||
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||||
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
||||||
bool isExplicit, bool isInline, bool isImplicitlyDeclared,
|
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
|
||||||
bool isConstexpr,
|
bool isConstexpr,
|
||||||
InheritedConstructor Inherited = InheritedConstructor());
|
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.
|
/// Iterates through the member/base initializer list.
|
||||||
using init_iterator = CXXCtorInitializer **;
|
using init_iterator = CXXCtorInitializer **;
|
||||||
|
|
||||||
|
@ -2600,11 +2696,6 @@ public:
|
||||||
CtorInitializers = Initializers;
|
CtorInitializers = Initializers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether this function is explicit.
|
|
||||||
bool isExplicit() const {
|
|
||||||
return getCanonicalDecl()->isExplicitSpecified();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Determine whether this constructor is a delegating constructor.
|
/// Determine whether this constructor is a delegating constructor.
|
||||||
bool isDelegatingConstructor() const {
|
bool isDelegatingConstructor() const {
|
||||||
return (getNumCtorInitializers() == 1) &&
|
return (getNumCtorInitializers() == 1) &&
|
||||||
|
@ -2783,34 +2874,39 @@ public:
|
||||||
class CXXConversionDecl : public CXXMethodDecl {
|
class CXXConversionDecl : public CXXMethodDecl {
|
||||||
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
CXXConversionDecl(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||||
const DeclarationNameInfo &NameInfo, QualType T,
|
const DeclarationNameInfo &NameInfo, QualType T,
|
||||||
TypeSourceInfo *TInfo, bool isInline,
|
TypeSourceInfo *TInfo, bool isInline, ExplicitSpecifier ES,
|
||||||
bool isExplicitSpecified, bool isConstexpr,
|
bool isConstexpr, SourceLocation EndLocation)
|
||||||
SourceLocation EndLocation)
|
|
||||||
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
|
: CXXMethodDecl(CXXConversion, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||||
SC_None, isInline, isConstexpr, EndLocation) {
|
SC_None, isInline, isConstexpr, EndLocation),
|
||||||
setExplicitSpecified(isExplicitSpecified);
|
ExplicitSpec(ES) {}
|
||||||
}
|
|
||||||
|
|
||||||
void anchor() override;
|
void anchor() override;
|
||||||
|
|
||||||
|
ExplicitSpecifier ExplicitSpec;
|
||||||
|
|
||||||
|
void setExplicitSpecifier(ExplicitSpecifier ES) { ExplicitSpec = ES; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
friend class ASTDeclReader;
|
friend class ASTDeclReader;
|
||||||
friend class ASTDeclWriter;
|
friend class ASTDeclWriter;
|
||||||
|
|
||||||
static CXXConversionDecl *Create(ASTContext &C, CXXRecordDecl *RD,
|
static CXXConversionDecl *
|
||||||
SourceLocation StartLoc,
|
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||||
const DeclarationNameInfo &NameInfo,
|
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
||||||
QualType T, TypeSourceInfo *TInfo,
|
bool isInline, ExplicitSpecifier ES, bool isConstexpr,
|
||||||
bool isInline, bool isExplicit,
|
SourceLocation EndLocation);
|
||||||
bool isConstexpr,
|
|
||||||
SourceLocation EndLocation);
|
|
||||||
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
static CXXConversionDecl *CreateDeserialized(ASTContext &C, unsigned ID);
|
||||||
|
|
||||||
/// Whether this function is explicit.
|
ExplicitSpecifier getExplicitSpecifier() {
|
||||||
bool isExplicit() const {
|
return getCanonicalDecl()->ExplicitSpec;
|
||||||
return getCanonicalDecl()->isExplicitSpecified();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
/// Returns the type that this conversion function is converting to.
|
||||||
QualType getConversionType() const {
|
QualType getConversionType() const {
|
||||||
return getType()->getAs<FunctionType>()->getReturnType();
|
return getType()->getAs<FunctionType>()->getReturnType();
|
||||||
|
|
|
@ -6171,6 +6171,9 @@ AST_MATCHER(CXXConstructorDecl, isDelegatingConstructor) {
|
||||||
AST_POLYMORPHIC_MATCHER(isExplicit,
|
AST_POLYMORPHIC_MATCHER(isExplicit,
|
||||||
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXConstructorDecl,
|
AST_POLYMORPHIC_SUPPORTED_TYPES(CXXConstructorDecl,
|
||||||
CXXConversionDecl)) {
|
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();
|
return Node.isExplicit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -150,6 +150,8 @@ def ext_warn_duplicate_declspec : ExtWarn<"%sub{duplicate_declspec}0">,
|
||||||
def warn_duplicate_declspec : Warning<"%sub{duplicate_declspec}0">,
|
def warn_duplicate_declspec : Warning<"%sub{duplicate_declspec}0">,
|
||||||
InGroup<DuplicateDeclSpecifier>;
|
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_friend_decl_spec : Error<"'%0' is invalid in friend declarations">;
|
||||||
|
|
||||||
def err_invalid_member_in_interface : Error<
|
def err_invalid_member_in_interface : Error<
|
||||||
|
|
|
@ -33,6 +33,10 @@ def err_asm_goto_not_supported_yet : Error<
|
||||||
|
|
||||||
let CategoryName = "Parse Issue" in {
|
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<
|
def ext_empty_translation_unit : Extension<
|
||||||
"ISO C requires a translation unit to contain at least one declaration">,
|
"ISO C requires a translation unit to contain at least one declaration">,
|
||||||
InGroup<DiagGroup<"empty-translation-unit">>;
|
InGroup<DiagGroup<"empty-translation-unit">>;
|
||||||
|
|
|
@ -83,11 +83,11 @@ def err_typecheck_converted_constant_expression_indirect : Error<
|
||||||
"bind reference to a temporary">;
|
"bind reference to a temporary">;
|
||||||
def err_expr_not_cce : Error<
|
def err_expr_not_cce : Error<
|
||||||
"%select{case value|enumerator value|non-type template argument|"
|
"%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">;
|
"is not a constant expression">;
|
||||||
def ext_cce_narrowing : ExtWarn<
|
def ext_cce_narrowing : ExtWarn<
|
||||||
"%select{case value|enumerator value|non-type template argument|"
|
"%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|"
|
"%select{cannot be narrowed from type %2 to %3|"
|
||||||
"evaluates to %2, which cannot be narrowed to type %3}1">,
|
"evaluates to %2, which cannot be narrowed to type %3}1">,
|
||||||
InGroup<CXX11Narrowing>, DefaultError, SFINAEFailure;
|
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">;
|
"deduction guide must be declared in the same scope as template %q0">;
|
||||||
def err_deduction_guide_defines_function : Error<
|
def err_deduction_guide_defines_function : Error<
|
||||||
"deduction guide cannot have a function definition">;
|
"deduction guide cannot have a function definition">;
|
||||||
def err_deduction_guide_explicit_mismatch : Error<
|
def err_deduction_guide_redeclared : Error<
|
||||||
"deduction guide is %select{not |}0declared 'explicit' but "
|
"redeclaration of deduction guide">;
|
||||||
"previous declaration was%select{ not|}0">;
|
|
||||||
def err_deduction_guide_specialized : Error<"deduction guide cannot be "
|
def err_deduction_guide_specialized : Error<"deduction guide cannot be "
|
||||||
"%select{explicitly instantiated|explicitly specialized}0">;
|
"%select{explicitly instantiated|explicitly specialized}0">;
|
||||||
def err_deduction_guide_template_not_deducible : Error<
|
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 qualifiers (expected %5 but found %6)"
|
||||||
"| has different exception specification}4">;
|
"| 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<
|
def note_ovl_candidate_inherited_constructor : Note<
|
||||||
"constructor from base class %0 inherited here">;
|
"constructor from base class %0 inherited here">;
|
||||||
def note_ovl_candidate_inherited_constructor_slice : Note<
|
def note_ovl_candidate_inherited_constructor_slice : Note<
|
||||||
|
|
|
@ -20,6 +20,14 @@
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
|
||||||
namespace clang {
|
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.
|
/// Specifies the width of a type, e.g., short, long, or long long.
|
||||||
enum TypeSpecifierWidth {
|
enum TypeSpecifierWidth {
|
||||||
TSW_unspecified,
|
TSW_unspecified,
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#ifndef LLVM_CLANG_SEMA_DECLSPEC_H
|
#ifndef LLVM_CLANG_SEMA_DECLSPEC_H
|
||||||
#define LLVM_CLANG_SEMA_DECLSPEC_H
|
#define LLVM_CLANG_SEMA_DECLSPEC_H
|
||||||
|
|
||||||
|
#include "clang/AST/DeclCXX.h"
|
||||||
#include "clang/AST/NestedNameSpecifier.h"
|
#include "clang/AST/NestedNameSpecifier.h"
|
||||||
#include "clang/Basic/ExceptionSpecificationType.h"
|
#include "clang/Basic/ExceptionSpecificationType.h"
|
||||||
#include "clang/Basic/Lambda.h"
|
#include "clang/Basic/Lambda.h"
|
||||||
|
@ -356,7 +357,6 @@ private:
|
||||||
unsigned FS_inline_specified : 1;
|
unsigned FS_inline_specified : 1;
|
||||||
unsigned FS_forceinline_specified: 1;
|
unsigned FS_forceinline_specified: 1;
|
||||||
unsigned FS_virtual_specified : 1;
|
unsigned FS_virtual_specified : 1;
|
||||||
unsigned FS_explicit_specified : 1;
|
|
||||||
unsigned FS_noreturn_specified : 1;
|
unsigned FS_noreturn_specified : 1;
|
||||||
|
|
||||||
// friend-specifier
|
// friend-specifier
|
||||||
|
@ -371,6 +371,9 @@ private:
|
||||||
Expr *ExprRep;
|
Expr *ExprRep;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ExplicitSpecifier - Store information about explicit spicifer.
|
||||||
|
ExplicitSpecifier FS_explicit_specifier;
|
||||||
|
|
||||||
// attributes.
|
// attributes.
|
||||||
ParsedAttributes Attrs;
|
ParsedAttributes Attrs;
|
||||||
|
|
||||||
|
@ -393,6 +396,7 @@ private:
|
||||||
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc,
|
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc,
|
||||||
TQ_unalignedLoc;
|
TQ_unalignedLoc;
|
||||||
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
|
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
|
||||||
|
SourceLocation FS_explicitCloseParenLoc;
|
||||||
SourceLocation FS_forceinlineLoc;
|
SourceLocation FS_forceinlineLoc;
|
||||||
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
|
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
|
||||||
SourceLocation TQ_pipeLoc;
|
SourceLocation TQ_pipeLoc;
|
||||||
|
@ -420,31 +424,18 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
DeclSpec(AttributeFactory &attrFactory)
|
DeclSpec(AttributeFactory &attrFactory)
|
||||||
: StorageClassSpec(SCS_unspecified),
|
: StorageClassSpec(SCS_unspecified),
|
||||||
ThreadStorageClassSpec(TSCS_unspecified),
|
ThreadStorageClassSpec(TSCS_unspecified),
|
||||||
SCS_extern_in_linkage_spec(false),
|
SCS_extern_in_linkage_spec(false), TypeSpecWidth(TSW_unspecified),
|
||||||
TypeSpecWidth(TSW_unspecified),
|
TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified),
|
||||||
TypeSpecComplex(TSC_unspecified),
|
TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
|
||||||
TypeSpecSign(TSS_unspecified),
|
TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
|
||||||
TypeSpecType(TST_unspecified),
|
TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified),
|
||||||
TypeAltiVecVector(false),
|
FS_inline_specified(false), FS_forceinline_specified(false),
|
||||||
TypeAltiVecPixel(false),
|
FS_virtual_specified(false), FS_noreturn_specified(false),
|
||||||
TypeAltiVecBool(false),
|
Friend_specified(false), Constexpr_specified(false),
|
||||||
TypeSpecOwned(false),
|
FS_explicit_specifier(), Attrs(attrFactory), writtenBS(),
|
||||||
TypeSpecPipe(false),
|
ObjCQualifiers(nullptr) {}
|
||||||
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) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// storage-class-specifier
|
// storage-class-specifier
|
||||||
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
|
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
|
||||||
|
@ -570,11 +561,22 @@ public:
|
||||||
return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc;
|
return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExplicitSpecifier getExplicitSpecifier() const {
|
||||||
|
return FS_explicit_specifier;
|
||||||
|
}
|
||||||
|
|
||||||
bool isVirtualSpecified() const { return FS_virtual_specified; }
|
bool isVirtualSpecified() const { return FS_virtual_specified; }
|
||||||
SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; }
|
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; }
|
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; }
|
bool isNoreturnSpecified() const { return FS_noreturn_specified; }
|
||||||
SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
|
SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
|
||||||
|
@ -586,8 +588,9 @@ public:
|
||||||
FS_forceinlineLoc = SourceLocation();
|
FS_forceinlineLoc = SourceLocation();
|
||||||
FS_virtual_specified = false;
|
FS_virtual_specified = false;
|
||||||
FS_virtualLoc = SourceLocation();
|
FS_virtualLoc = SourceLocation();
|
||||||
FS_explicit_specified = false;
|
FS_explicit_specifier = ExplicitSpecifier();
|
||||||
FS_explicitLoc = SourceLocation();
|
FS_explicitLoc = SourceLocation();
|
||||||
|
FS_explicitCloseParenLoc = SourceLocation();
|
||||||
FS_noreturn_specified = false;
|
FS_noreturn_specified = false;
|
||||||
FS_noreturnLoc = SourceLocation();
|
FS_noreturnLoc = SourceLocation();
|
||||||
}
|
}
|
||||||
|
@ -706,7 +709,8 @@ public:
|
||||||
bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
|
bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
|
||||||
unsigned &DiagID);
|
unsigned &DiagID);
|
||||||
bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
|
bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
|
||||||
unsigned &DiagID);
|
unsigned &DiagID, ExplicitSpecifier ExplicitSpec,
|
||||||
|
SourceLocation CloseParenLoc);
|
||||||
bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
|
bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
|
||||||
unsigned &DiagID);
|
unsigned &DiagID);
|
||||||
|
|
||||||
|
|
|
@ -705,6 +705,11 @@ class Sema;
|
||||||
/// attribute disabled it.
|
/// attribute disabled it.
|
||||||
ovl_fail_enable_if,
|
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.
|
/// This candidate was not viable because its address could not be taken.
|
||||||
ovl_fail_addr_not_available,
|
ovl_fail_addr_not_available,
|
||||||
|
|
||||||
|
|
|
@ -2744,7 +2744,8 @@ public:
|
||||||
CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
|
CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
|
||||||
CCEK_TemplateArg, ///< Value of a non-type template parameter.
|
CCEK_TemplateArg, ///< Value of a non-type template parameter.
|
||||||
CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator.
|
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,
|
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
|
||||||
llvm::APSInt &Value, CCEKind CCE);
|
llvm::APSInt &Value, CCEKind CCE);
|
||||||
|
@ -2867,6 +2868,7 @@ public:
|
||||||
bool SuppressUserConversions = false,
|
bool SuppressUserConversions = false,
|
||||||
bool PartialOverloading = false,
|
bool PartialOverloading = false,
|
||||||
bool AllowExplicit = false,
|
bool AllowExplicit = false,
|
||||||
|
bool AllowExplicitConversion = false,
|
||||||
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
|
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
|
||||||
ConversionSequenceList EarlyConversions = None);
|
ConversionSequenceList EarlyConversions = None);
|
||||||
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
|
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
|
||||||
|
@ -2905,7 +2907,7 @@ public:
|
||||||
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
|
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
|
||||||
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
|
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
|
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
|
||||||
bool PartialOverloading = false,
|
bool PartialOverloading = false, bool AllowExplicit = false,
|
||||||
ADLCallKind IsADLCandidate = ADLCallKind::NotADL);
|
ADLCallKind IsADLCandidate = ADLCallKind::NotADL);
|
||||||
bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
|
bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
|
||||||
ArrayRef<QualType> ParamTypes,
|
ArrayRef<QualType> ParamTypes,
|
||||||
|
@ -2917,20 +2919,16 @@ public:
|
||||||
QualType ObjectType = QualType(),
|
QualType ObjectType = QualType(),
|
||||||
Expr::Classification
|
Expr::Classification
|
||||||
ObjectClassification = {});
|
ObjectClassification = {});
|
||||||
void AddConversionCandidate(CXXConversionDecl *Conversion,
|
void AddConversionCandidate(
|
||||||
DeclAccessPair FoundDecl,
|
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
|
||||||
CXXRecordDecl *ActingContext,
|
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
|
||||||
Expr *From, QualType ToType,
|
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
|
||||||
OverloadCandidateSet& CandidateSet,
|
bool AllowExplicit, bool AllowResultConversion = true);
|
||||||
bool AllowObjCConversionOnExplicit,
|
void AddTemplateConversionCandidate(
|
||||||
bool AllowResultConversion = true);
|
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
|
||||||
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
|
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
|
||||||
DeclAccessPair FoundDecl,
|
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
|
||||||
CXXRecordDecl *ActingContext,
|
bool AllowExplicit, bool AllowResultConversion = true);
|
||||||
Expr *From, QualType ToType,
|
|
||||||
OverloadCandidateSet &CandidateSet,
|
|
||||||
bool AllowObjCConversionOnExplicit,
|
|
||||||
bool AllowResultConversion = true);
|
|
||||||
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
|
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
|
||||||
DeclAccessPair FoundDecl,
|
DeclAccessPair FoundDecl,
|
||||||
CXXRecordDecl *ActingContext,
|
CXXRecordDecl *ActingContext,
|
||||||
|
@ -10120,6 +10118,14 @@ public:
|
||||||
ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E,
|
ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E,
|
||||||
bool IsConstexpr = false);
|
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
|
/// DiagnoseAssignmentAsCondition - Given that an expression is
|
||||||
/// being used as a boolean condition, warn if it's an assignment.
|
/// being used as a boolean condition, warn if it's an assignment.
|
||||||
void DiagnoseAssignmentAsCondition(Expr *E);
|
void DiagnoseAssignmentAsCondition(Expr *E);
|
||||||
|
|
|
@ -1438,9 +1438,6 @@ namespace serialization {
|
||||||
/// A CXXConstructorDecl record.
|
/// A CXXConstructorDecl record.
|
||||||
DECL_CXX_CONSTRUCTOR,
|
DECL_CXX_CONSTRUCTOR,
|
||||||
|
|
||||||
/// A CXXConstructorDecl record for an inherited constructor.
|
|
||||||
DECL_CXX_INHERITED_CONSTRUCTOR,
|
|
||||||
|
|
||||||
/// A CXXDestructorDecl record.
|
/// A CXXDestructorDecl record.
|
||||||
DECL_CXX_DESTRUCTOR,
|
DECL_CXX_DESTRUCTOR,
|
||||||
|
|
||||||
|
|
|
@ -2430,6 +2430,14 @@ public:
|
||||||
ID);
|
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,
|
void readExceptionSpec(SmallVectorImpl<QualType> &ExceptionStorage,
|
||||||
FunctionProtoType::ExceptionSpecInfo &ESI) {
|
FunctionProtoType::ExceptionSpecInfo &ESI) {
|
||||||
return Reader->readExceptionSpec(*F, ExceptionStorage, ESI, Record, Idx);
|
return Reader->readExceptionSpec(*F, ExceptionStorage, ESI, Record, Idx);
|
||||||
|
|
|
@ -3047,11 +3047,20 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
// Create the imported function.
|
// Create the imported function.
|
||||||
FunctionDecl *ToFunction = nullptr;
|
FunctionDecl *ToFunction = nullptr;
|
||||||
if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
|
if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||||
|
Expr *ExplicitExpr = nullptr;
|
||||||
|
if (FromConstructor->getExplicitSpecifier().getExpr()) {
|
||||||
|
auto Imp = importSeq(FromConstructor->getExplicitSpecifier().getExpr());
|
||||||
|
if (!Imp)
|
||||||
|
return Imp.takeError();
|
||||||
|
std::tie(ExplicitExpr) = *Imp;
|
||||||
|
}
|
||||||
if (GetImportedOrCreateDecl<CXXConstructorDecl>(
|
if (GetImportedOrCreateDecl<CXXConstructorDecl>(
|
||||||
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
|
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
|
||||||
ToInnerLocStart, NameInfo, T, TInfo,
|
ToInnerLocStart, NameInfo, T, TInfo,
|
||||||
FromConstructor->isExplicit(),
|
ExplicitSpecifier(
|
||||||
D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
|
ExplicitExpr,
|
||||||
|
FromConstructor->getExplicitSpecifier().getKind()),
|
||||||
|
D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
|
||||||
return ToFunction;
|
return ToFunction;
|
||||||
} else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
|
} else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {
|
||||||
|
|
||||||
|
@ -3077,10 +3086,19 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg);
|
ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg);
|
||||||
} else if (CXXConversionDecl *FromConversion =
|
} else if (CXXConversionDecl *FromConversion =
|
||||||
dyn_cast<CXXConversionDecl>(D)) {
|
dyn_cast<CXXConversionDecl>(D)) {
|
||||||
|
Expr *ExplicitExpr = nullptr;
|
||||||
|
if (FromConversion->getExplicitSpecifier().getExpr()) {
|
||||||
|
auto Imp = importSeq(FromConversion->getExplicitSpecifier().getExpr());
|
||||||
|
if (!Imp)
|
||||||
|
return Imp.takeError();
|
||||||
|
std::tie(ExplicitExpr) = *Imp;
|
||||||
|
}
|
||||||
if (GetImportedOrCreateDecl<CXXConversionDecl>(
|
if (GetImportedOrCreateDecl<CXXConversionDecl>(
|
||||||
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
|
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
|
||||||
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
|
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
|
||||||
FromConversion->isExplicit(), D->isConstexpr(), SourceLocation()))
|
ExplicitSpecifier(ExplicitExpr,
|
||||||
|
FromConversion->getExplicitSpecifier().getKind()),
|
||||||
|
D->isConstexpr(), SourceLocation()))
|
||||||
return ToFunction;
|
return ToFunction;
|
||||||
} else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
|
} else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
|
||||||
if (GetImportedOrCreateDecl<CXXMethodDecl>(
|
if (GetImportedOrCreateDecl<CXXMethodDecl>(
|
||||||
|
|
|
@ -955,13 +955,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
|
||||||
|
|
||||||
if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
|
if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
|
||||||
auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
|
auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
|
||||||
if (Constructor1->isExplicit() != Constructor2->isExplicit())
|
if (!Constructor1->getExplicitSpecifier().isEquivalent(
|
||||||
|
Constructor2->getExplicitSpecifier()))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
|
if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
|
||||||
auto *Conversion2 = cast<CXXConversionDecl>(Method2);
|
auto *Conversion2 = cast<CXXConversionDecl>(Method2);
|
||||||
if (Conversion1->isExplicit() != Conversion2->isExplicit())
|
if (!Conversion1->getExplicitSpecifier().isEquivalent(
|
||||||
|
Conversion2->getExplicitSpecifier()))
|
||||||
return false;
|
return false;
|
||||||
if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
|
if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
|
||||||
Conversion2->getConversionType()))
|
Conversion2->getConversionType()))
|
||||||
|
|
|
@ -2713,7 +2713,6 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
|
||||||
FunctionDeclBits.SClass = S;
|
FunctionDeclBits.SClass = S;
|
||||||
FunctionDeclBits.IsInline = isInlineSpecified;
|
FunctionDeclBits.IsInline = isInlineSpecified;
|
||||||
FunctionDeclBits.IsInlineSpecified = isInlineSpecified;
|
FunctionDeclBits.IsInlineSpecified = isInlineSpecified;
|
||||||
FunctionDeclBits.IsExplicitSpecified = false;
|
|
||||||
FunctionDeclBits.IsVirtualAsWritten = false;
|
FunctionDeclBits.IsVirtualAsWritten = false;
|
||||||
FunctionDeclBits.IsPure = false;
|
FunctionDeclBits.IsPure = false;
|
||||||
FunctionDeclBits.HasInheritedPrototype = false;
|
FunctionDeclBits.HasInheritedPrototype = false;
|
||||||
|
|
|
@ -1862,19 +1862,47 @@ bool CXXRecordDecl::mayBeAbstract() const {
|
||||||
|
|
||||||
void CXXDeductionGuideDecl::anchor() {}
|
void CXXDeductionGuideDecl::anchor() {}
|
||||||
|
|
||||||
|
bool ExplicitSpecifier::isEquivalent(const ExplicitSpecifier Other) const {
|
||||||
|
if ((getKind() != Other.getKind() ||
|
||||||
|
getKind() == ExplicitSpecKind::Unresolved)) {
|
||||||
|
if (getKind() == ExplicitSpecKind::Unresolved &&
|
||||||
|
Other.getKind() == ExplicitSpecKind::Unresolved) {
|
||||||
|
ODRHash SelfHash, OtherHash;
|
||||||
|
SelfHash.AddStmt(getExpr());
|
||||||
|
OtherHash.AddStmt(Other.getExpr());
|
||||||
|
return SelfHash.CalculateHash() == OtherHash.CalculateHash();
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) {
|
||||||
|
switch (Function->getDeclKind()) {
|
||||||
|
case Decl::Kind::CXXConstructor:
|
||||||
|
return cast<CXXConstructorDecl>(Function)->getExplicitSpecifier();
|
||||||
|
case Decl::Kind::CXXConversion:
|
||||||
|
return cast<CXXConversionDecl>(Function)->getExplicitSpecifier();
|
||||||
|
case Decl::Kind::CXXDeductionGuide:
|
||||||
|
return cast<CXXDeductionGuideDecl>(Function)->getExplicitSpecifier();
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
|
CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
|
||||||
ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit,
|
ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
|
||||||
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
|
||||||
SourceLocation EndLocation) {
|
TypeSourceInfo *TInfo, SourceLocation EndLocation) {
|
||||||
return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit,
|
return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T,
|
||||||
NameInfo, T, TInfo, EndLocation);
|
TInfo, EndLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
|
CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
|
||||||
unsigned ID) {
|
unsigned ID) {
|
||||||
return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false,
|
return new (C, ID) CXXDeductionGuideDecl(
|
||||||
DeclarationNameInfo(), QualType(),
|
C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
|
||||||
nullptr, SourceLocation());
|
QualType(), nullptr, SourceLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXMethodDecl::anchor() {}
|
void CXXMethodDecl::anchor() {}
|
||||||
|
@ -2312,47 +2340,54 @@ SourceRange CXXCtorInitializer::getSourceRange() const {
|
||||||
CXXConstructorDecl::CXXConstructorDecl(
|
CXXConstructorDecl::CXXConstructorDecl(
|
||||||
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||||
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
||||||
bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared,
|
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
|
||||||
bool isConstexpr, InheritedConstructor Inherited)
|
bool isConstexpr, InheritedConstructor Inherited)
|
||||||
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
|
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
|
||||||
SC_None, isInline, isConstexpr, SourceLocation()) {
|
SC_None, isInline, isConstexpr, SourceLocation()) {
|
||||||
setNumCtorInitializers(0);
|
setNumCtorInitializers(0);
|
||||||
setInheritingConstructor(static_cast<bool>(Inherited));
|
setInheritingConstructor(static_cast<bool>(Inherited));
|
||||||
setImplicit(isImplicitlyDeclared);
|
setImplicit(isImplicitlyDeclared);
|
||||||
|
CXXConstructorDeclBits.HasTrailingExplicitSpecifier = ES.getExpr() ? 1 : 0;
|
||||||
if (Inherited)
|
if (Inherited)
|
||||||
*getTrailingObjects<InheritedConstructor>() = Inherited;
|
*getTrailingObjects<InheritedConstructor>() = Inherited;
|
||||||
setExplicitSpecified(isExplicitSpecified);
|
setExplicitSpecifier(ES);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXConstructorDecl::anchor() {}
|
void CXXConstructorDecl::anchor() {}
|
||||||
|
|
||||||
CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
|
CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
|
||||||
unsigned ID,
|
unsigned ID,
|
||||||
bool Inherited) {
|
uint64_t AllocKind) {
|
||||||
unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited);
|
bool hasTraillingExplicit = static_cast<bool>(AllocKind & TAKHasTailExplicit);
|
||||||
|
bool isInheritingConstructor =
|
||||||
|
static_cast<bool>(AllocKind & TAKInheritsConstructor);
|
||||||
|
unsigned Extra =
|
||||||
|
additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
|
||||||
|
isInheritingConstructor, hasTraillingExplicit);
|
||||||
auto *Result = new (C, ID, Extra) CXXConstructorDecl(
|
auto *Result = new (C, ID, Extra) CXXConstructorDecl(
|
||||||
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
|
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
|
||||||
false, false, false, false, InheritedConstructor());
|
ExplicitSpecifier(), false, false, false, InheritedConstructor());
|
||||||
Result->setInheritingConstructor(Inherited);
|
Result->setInheritingConstructor(isInheritingConstructor);
|
||||||
|
Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
|
||||||
|
hasTraillingExplicit;
|
||||||
|
Result->setExplicitSpecifier(ExplicitSpecifier());
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
CXXConstructorDecl *
|
CXXConstructorDecl *CXXConstructorDecl::Create(
|
||||||
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||||
SourceLocation StartLoc,
|
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
||||||
const DeclarationNameInfo &NameInfo,
|
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
|
||||||
QualType T, TypeSourceInfo *TInfo,
|
bool isConstexpr, InheritedConstructor Inherited) {
|
||||||
bool isExplicit, bool isInline,
|
|
||||||
bool isImplicitlyDeclared, bool isConstexpr,
|
|
||||||
InheritedConstructor Inherited) {
|
|
||||||
assert(NameInfo.getName().getNameKind()
|
assert(NameInfo.getName().getNameKind()
|
||||||
== DeclarationName::CXXConstructorName &&
|
== DeclarationName::CXXConstructorName &&
|
||||||
"Name must refer to a constructor");
|
"Name must refer to a constructor");
|
||||||
unsigned Extra =
|
unsigned Extra =
|
||||||
additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0);
|
additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
|
||||||
return new (C, RD, Extra) CXXConstructorDecl(
|
Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
|
||||||
C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline,
|
return new (C, RD, Extra)
|
||||||
isImplicitlyDeclared, isConstexpr, Inherited);
|
CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
|
||||||
|
isImplicitlyDeclared, isConstexpr, Inherited);
|
||||||
}
|
}
|
||||||
|
|
||||||
CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
|
CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
|
||||||
|
@ -2503,25 +2538,21 @@ void CXXConversionDecl::anchor() {}
|
||||||
|
|
||||||
CXXConversionDecl *
|
CXXConversionDecl *
|
||||||
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
||||||
return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(),
|
return new (C, ID) CXXConversionDecl(
|
||||||
DeclarationNameInfo(), QualType(),
|
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
|
||||||
nullptr, false, false, false,
|
false, ExplicitSpecifier(), false, SourceLocation());
|
||||||
SourceLocation());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CXXConversionDecl *
|
CXXConversionDecl *CXXConversionDecl::Create(
|
||||||
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
|
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
|
||||||
SourceLocation StartLoc,
|
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
|
||||||
const DeclarationNameInfo &NameInfo,
|
bool isInline, ExplicitSpecifier ES, bool isConstexpr,
|
||||||
QualType T, TypeSourceInfo *TInfo,
|
SourceLocation EndLocation) {
|
||||||
bool isInline, bool isExplicit,
|
|
||||||
bool isConstexpr, SourceLocation EndLocation) {
|
|
||||||
assert(NameInfo.getName().getNameKind()
|
assert(NameInfo.getName().getNameKind()
|
||||||
== DeclarationName::CXXConversionFunctionName &&
|
== DeclarationName::CXXConversionFunctionName &&
|
||||||
"Name must refer to a conversion function");
|
"Name must refer to a conversion function");
|
||||||
return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
|
return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
|
||||||
isInline, isExplicit, isConstexpr,
|
isInline, ES, isConstexpr, EndLocation);
|
||||||
EndLocation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
|
bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
|
||||||
|
|
|
@ -552,6 +552,21 @@ void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
if (!D->getDescribedFunctionTemplate() &&
|
if (!D->getDescribedFunctionTemplate() &&
|
||||||
!D->isFunctionTemplateSpecialization())
|
!D->isFunctionTemplateSpecialization())
|
||||||
|
@ -582,10 +597,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
if (D->isVirtualAsWritten()) Out << "virtual ";
|
if (D->isVirtualAsWritten()) Out << "virtual ";
|
||||||
if (D->isModulePrivate()) Out << "__module_private__ ";
|
if (D->isModulePrivate()) Out << "__module_private__ ";
|
||||||
if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
|
if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
|
||||||
if ((CDecl && CDecl->isExplicitSpecified()) ||
|
ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
|
||||||
(ConversionDecl && ConversionDecl->isExplicitSpecified()) ||
|
if (ExplicitSpec.isSpecified())
|
||||||
(GuideDecl && GuideDecl->isExplicitSpecified()))
|
printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation);
|
||||||
Out << "explicit ";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PrintingPolicy SubPolicy(Policy);
|
PrintingPolicy SubPolicy(Policy);
|
||||||
|
|
|
@ -540,6 +540,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
|
||||||
Builder.defineMacro("__cpp_template_template_args", "201611L");
|
Builder.defineMacro("__cpp_template_template_args", "201611L");
|
||||||
|
|
||||||
// C++20 features.
|
// C++20 features.
|
||||||
|
if (LangOpts.CPlusPlus2a)
|
||||||
|
Builder.defineMacro("__cpp_conditional_explicit", "201806L");
|
||||||
if (LangOpts.Char8)
|
if (LangOpts.Char8)
|
||||||
Builder.defineMacro("__cpp_char8_t", "201811L");
|
Builder.defineMacro("__cpp_char8_t", "201811L");
|
||||||
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
|
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
|
||||||
|
|
|
@ -2442,12 +2442,12 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
|
||||||
Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
|
Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
|
||||||
if (DS.isVirtualSpecified())
|
if (DS.isVirtualSpecified())
|
||||||
Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
|
Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
|
||||||
if (DS.isExplicitSpecified())
|
if (DS.hasExplicitSpecifier())
|
||||||
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
|
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
|
||||||
DS.ClearFunctionSpecs();
|
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) {
|
if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) {
|
||||||
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
|
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
|
||||||
DS.ClearConstexprSpec();
|
DS.ClearConstexprSpec();
|
||||||
|
@ -2962,9 +2962,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||||
while (1) {
|
while (1) {
|
||||||
bool isInvalid = false;
|
bool isInvalid = false;
|
||||||
bool isStorageClass = false;
|
bool isStorageClass = false;
|
||||||
|
bool isAlreadyConsumed = false;
|
||||||
const char *PrevSpec = nullptr;
|
const char *PrevSpec = nullptr;
|
||||||
unsigned DiagID = 0;
|
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
|
// 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
|
// implementation for VS2013 uses _Atomic as an identifier for one of the
|
||||||
// classes in <atomic>.
|
// classes in <atomic>.
|
||||||
|
@ -3515,9 +3519,34 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||||
isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
|
isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case tok::kw_explicit:
|
case tok::kw_explicit: {
|
||||||
isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID);
|
SourceLocation ExplicitLoc = Loc;
|
||||||
|
SourceLocation CloseParenLoc;
|
||||||
|
ExplicitSpecifier ExplicitSpec(nullptr, ExplicitSpecKind::ResolvedTrue);
|
||||||
|
isAlreadyConsumed = true;
|
||||||
|
RangeEnd = ExplicitLoc;
|
||||||
|
ConsumeToken(); // kw_explicit
|
||||||
|
if (Tok.is(tok::l_paren)) {
|
||||||
|
if (getLangOpts().CPlusPlus2a) {
|
||||||
|
ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
|
||||||
|
BalancedDelimiterTracker Tracker(*this, tok::l_paren);
|
||||||
|
Tracker.consumeOpen();
|
||||||
|
ExplicitExpr = ParseConstantExpression();
|
||||||
|
RangeEnd = Tok.getLocation();
|
||||||
|
if (ExplicitExpr.isUsable()) {
|
||||||
|
CloseParenLoc = Tok.getLocation();
|
||||||
|
Tracker.consumeClose();
|
||||||
|
ExplicitSpec =
|
||||||
|
Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
|
||||||
|
} else
|
||||||
|
Tracker.skipToEnd();
|
||||||
|
} else
|
||||||
|
Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
|
||||||
|
}
|
||||||
|
isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
|
||||||
|
ExplicitSpec, CloseParenLoc);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case tok::kw__Noreturn:
|
case tok::kw__Noreturn:
|
||||||
if (!getLangOpts().C11)
|
if (!getLangOpts().C11)
|
||||||
Diag(Loc, diag::ext_c11_noreturn);
|
Diag(Loc, diag::ext_c11_noreturn);
|
||||||
|
@ -3861,25 +3890,32 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
|
||||||
// If a type specifier follows, it will be diagnosed elsewhere.
|
// If a type specifier follows, it will be diagnosed elsewhere.
|
||||||
continue;
|
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 the specifier wasn't legal, issue a diagnostic.
|
||||||
if (isInvalid) {
|
if (isInvalid) {
|
||||||
assert(PrevSpec && "Method did not return previous specifier!");
|
assert(PrevSpec && "Method did not return previous specifier!");
|
||||||
assert(DiagID);
|
assert(DiagID);
|
||||||
|
|
||||||
if (DiagID == diag::ext_duplicate_declspec ||
|
if (DiagID == diag::ext_duplicate_declspec ||
|
||||||
DiagID == diag::ext_warn_duplicate_declspec)
|
DiagID == diag::ext_warn_duplicate_declspec ||
|
||||||
Diag(Tok, DiagID)
|
DiagID == diag::err_duplicate_declspec)
|
||||||
<< PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
|
Diag(Loc, DiagID) << PrevSpec
|
||||||
|
<< FixItHint::CreateRemoval(
|
||||||
|
SourceRange(Loc, DS.getEndLoc()));
|
||||||
else if (DiagID == diag::err_opencl_unknown_type_specifier) {
|
else if (DiagID == diag::err_opencl_unknown_type_specifier) {
|
||||||
Diag(Tok, DiagID) << getLangOpts().OpenCLCPlusPlus
|
Diag(Loc, DiagID) << getLangOpts().OpenCLCPlusPlus
|
||||||
<< getLangOpts().getOpenCLVersionTuple().getAsString()
|
<< getLangOpts().getOpenCLVersionTuple().getAsString()
|
||||||
<< PrevSpec << isStorageClass;
|
<< PrevSpec << isStorageClass;
|
||||||
} else
|
} else
|
||||||
Diag(Tok, DiagID) << PrevSpec;
|
Diag(Loc, DiagID) << PrevSpec;
|
||||||
}
|
}
|
||||||
|
|
||||||
DS.SetRangeEnd(Tok.getLocation());
|
if (DiagID != diag::err_bool_redeclaration && !isAlreadyConsumed)
|
||||||
if (DiagID != diag::err_bool_redeclaration)
|
|
||||||
// After an error the next token can be an annotation token.
|
// After an error the next token can be an annotation token.
|
||||||
ConsumeAnyToken();
|
ConsumeAnyToken();
|
||||||
|
|
||||||
|
|
|
@ -445,7 +445,7 @@ unsigned DeclSpec::getParsedSpecifiers() const {
|
||||||
if (hasTypeSpecifier())
|
if (hasTypeSpecifier())
|
||||||
Res |= PQ_TypeSpecifier;
|
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)
|
FS_noreturn_specified || FS_forceinline_specified)
|
||||||
Res |= PQ_FunctionSpecifier;
|
Res |= PQ_FunctionSpecifier;
|
||||||
return Res;
|
return Res;
|
||||||
|
@ -944,17 +944,24 @@ bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc,
|
bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc,
|
||||||
const char *&PrevSpec,
|
const char *&PrevSpec, unsigned &DiagID,
|
||||||
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
|
// 'explicit explicit' is ok, but warn as this is likely not what the user
|
||||||
// intended.
|
// intended.
|
||||||
if (FS_explicit_specified) {
|
if (hasExplicitSpecifier()) {
|
||||||
DiagID = diag::warn_duplicate_declspec;
|
DiagID = (ExplicitSpec.getExpr() || FS_explicit_specifier.getExpr())
|
||||||
|
? diag::err_duplicate_declspec
|
||||||
|
: diag::ext_warn_duplicate_declspec;
|
||||||
PrevSpec = "explicit";
|
PrevSpec = "explicit";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
FS_explicit_specified = true;
|
FS_explicit_specifier = ExplicitSpec;
|
||||||
FS_explicitLoc = Loc;
|
FS_explicitLoc = Loc;
|
||||||
|
FS_explicitCloseParenLoc = CloseParenLoc;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,23 +1300,26 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
|
||||||
// The explicit specifier shall be used only in the declaration of
|
// The explicit specifier shall be used only in the declaration of
|
||||||
// a constructor or conversion function within its class
|
// a constructor or conversion function within its class
|
||||||
// definition;
|
// definition;
|
||||||
if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) {
|
if (isFriendSpecified() && (isVirtualSpecified() || hasExplicitSpecifier())) {
|
||||||
StringRef Keyword;
|
StringRef Keyword;
|
||||||
|
FixItHint Hint;
|
||||||
SourceLocation SCLoc;
|
SourceLocation SCLoc;
|
||||||
|
|
||||||
if (isVirtualSpecified()) {
|
if (isVirtualSpecified()) {
|
||||||
Keyword = "virtual";
|
Keyword = "virtual";
|
||||||
SCLoc = getVirtualSpecLoc();
|
SCLoc = getVirtualSpecLoc();
|
||||||
|
Hint = FixItHint::CreateRemoval(SCLoc);
|
||||||
} else {
|
} else {
|
||||||
Keyword = "explicit";
|
Keyword = "explicit";
|
||||||
SCLoc = getExplicitSpecLoc();
|
SCLoc = getExplicitSpecLoc();
|
||||||
|
Hint = FixItHint::CreateRemoval(getExplicitSpecRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
FixItHint Hint = FixItHint::CreateRemoval(SCLoc);
|
|
||||||
S.Diag(SCLoc, diag::err_friend_decl_spec)
|
S.Diag(SCLoc, diag::err_friend_decl_spec)
|
||||||
<< Keyword << Hint;
|
<< Keyword << Hint;
|
||||||
|
|
||||||
FS_virtual_specified = FS_explicit_specified = false;
|
FS_virtual_specified = false;
|
||||||
|
FS_explicit_specifier = ExplicitSpecifier();
|
||||||
FS_virtualLoc = FS_explicitLoc = SourceLocation();
|
FS_virtualLoc = FS_explicitLoc = SourceLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4961,13 +4961,15 @@ QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
|
||||||
AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
|
AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
|
||||||
CandidateSet,
|
CandidateSet,
|
||||||
/*SuppressUsedConversions=*/false,
|
/*SuppressUsedConversions=*/false,
|
||||||
/*PartialOverloading=*/true);
|
/*PartialOverloading=*/true,
|
||||||
|
/*AllowExplicit*/ true);
|
||||||
} else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
|
} else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
|
||||||
AddTemplateOverloadCandidate(
|
AddTemplateOverloadCandidate(
|
||||||
FTD, DeclAccessPair::make(FTD, C->getAccess()),
|
FTD, DeclAccessPair::make(FTD, C->getAccess()),
|
||||||
/*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,
|
/*ExplicitTemplateArgs=*/nullptr, Args, CandidateSet,
|
||||||
/*SuppressUsedConversions=*/false,
|
/*SuppressUsedConversions=*/false,
|
||||||
/*PartialOverloading=*/true);
|
/*PartialOverloading=*/true,
|
||||||
|
/*AllowExplicit*/ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5705,7 +5705,7 @@ void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) {
|
||||||
Diag(DS.getVirtualSpecLoc(),
|
Diag(DS.getVirtualSpecLoc(),
|
||||||
diag::err_virtual_non_function);
|
diag::err_virtual_non_function);
|
||||||
|
|
||||||
if (DS.isExplicitSpecified())
|
if (DS.hasExplicitSpecifier())
|
||||||
Diag(DS.getExplicitSpecLoc(),
|
Diag(DS.getExplicitSpecLoc(),
|
||||||
diag::err_explicit_non_function);
|
diag::err_explicit_non_function);
|
||||||
|
|
||||||
|
@ -7969,7 +7969,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
|
||||||
return NewFD;
|
return NewFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
|
ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
|
||||||
bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
|
bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
|
||||||
|
|
||||||
// Check that the return type is not an abstract class type.
|
// Check that the return type is not an abstract class type.
|
||||||
|
@ -7989,7 +7989,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
|
||||||
R = SemaRef.CheckConstructorDeclarator(D, R, SC);
|
R = SemaRef.CheckConstructorDeclarator(D, R, SC);
|
||||||
return CXXConstructorDecl::Create(
|
return CXXConstructorDecl::Create(
|
||||||
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
|
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
|
||||||
TInfo, isExplicit, isInline,
|
TInfo, ExplicitSpecifier, isInline,
|
||||||
/*isImplicitlyDeclared=*/false, isConstexpr);
|
/*isImplicitlyDeclared=*/false, isConstexpr);
|
||||||
|
|
||||||
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
|
} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
|
||||||
|
@ -8034,13 +8034,13 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
|
||||||
IsVirtualOkay = true;
|
IsVirtualOkay = true;
|
||||||
return CXXConversionDecl::Create(
|
return CXXConversionDecl::Create(
|
||||||
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
|
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
|
||||||
TInfo, isInline, isExplicit, isConstexpr, SourceLocation());
|
TInfo, isInline, ExplicitSpecifier, isConstexpr, SourceLocation());
|
||||||
|
|
||||||
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
|
} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
|
||||||
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
|
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);
|
||||||
|
|
||||||
return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
|
return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
|
||||||
isExplicit, NameInfo, R, TInfo,
|
ExplicitSpecifier, NameInfo, R, TInfo,
|
||||||
D.getEndLoc());
|
D.getEndLoc());
|
||||||
} else if (DC->isRecord()) {
|
} else if (DC->isRecord()) {
|
||||||
// If the name of the function is the same as the name of the record,
|
// If the name of the function is the same as the name of the record,
|
||||||
|
@ -8401,7 +8401,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
if (getLangOpts().CPlusPlus) {
|
if (getLangOpts().CPlusPlus) {
|
||||||
bool isInline = D.getDeclSpec().isInlineSpecified();
|
bool isInline = D.getDeclSpec().isInlineSpecified();
|
||||||
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
|
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
|
||||||
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
|
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
|
||||||
bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
|
bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
|
||||||
isFriend = D.getDeclSpec().isFriendSpecified();
|
isFriend = D.getDeclSpec().isFriendSpecified();
|
||||||
if (isFriend && !isInline && D.isFunctionDefinition()) {
|
if (isFriend && !isInline && D.isFunctionDefinition()) {
|
||||||
|
@ -8584,20 +8584,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
|
||||||
// The explicit specifier shall be used only in the declaration of a
|
// The explicit specifier shall be used only in the declaration of a
|
||||||
// constructor or conversion function within its class definition;
|
// constructor or conversion function within its class definition;
|
||||||
// see 12.3.1 and 12.3.2.
|
// see 12.3.1 and 12.3.2.
|
||||||
if (isExplicit && !NewFD->isInvalidDecl() &&
|
if (hasExplicit && !NewFD->isInvalidDecl() &&
|
||||||
!isa<CXXDeductionGuideDecl>(NewFD)) {
|
!isa<CXXDeductionGuideDecl>(NewFD)) {
|
||||||
if (!CurContext->isRecord()) {
|
if (!CurContext->isRecord()) {
|
||||||
// 'explicit' was specified outside of the class.
|
// 'explicit' was specified outside of the class.
|
||||||
Diag(D.getDeclSpec().getExplicitSpecLoc(),
|
Diag(D.getDeclSpec().getExplicitSpecLoc(),
|
||||||
diag::err_explicit_out_of_class)
|
diag::err_explicit_out_of_class)
|
||||||
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
|
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
|
||||||
} else if (!isa<CXXConstructorDecl>(NewFD) &&
|
} else if (!isa<CXXConstructorDecl>(NewFD) &&
|
||||||
!isa<CXXConversionDecl>(NewFD)) {
|
!isa<CXXConversionDecl>(NewFD)) {
|
||||||
// 'explicit' was specified on a function that wasn't a constructor
|
// 'explicit' was specified on a function that wasn't a constructor
|
||||||
// or conversion function.
|
// or conversion function.
|
||||||
Diag(D.getDeclSpec().getExplicitSpecLoc(),
|
Diag(D.getDeclSpec().getExplicitSpecLoc(),
|
||||||
diag::err_explicit_non_ctor_or_conv_function)
|
diag::err_explicit_non_ctor_or_conv_function)
|
||||||
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
|
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -657,14 +657,13 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: It's not clear what should happen if multiple declarations of a
|
// C++17 [temp.deduct.guide]p3:
|
||||||
// deduction guide have different explicitness. For now at least we simply
|
// Two deduction guide declarations in the same translation unit
|
||||||
// reject any case where the explicitness changes.
|
// for the same class template shall not have equivalent
|
||||||
auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New);
|
// parameter-declaration-clauses.
|
||||||
if (NewGuide && NewGuide->isExplicitSpecified() !=
|
if (isa<CXXDeductionGuideDecl>(New) &&
|
||||||
cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) {
|
!New->isFunctionTemplateSpecialization()) {
|
||||||
Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
|
Diag(New->getLocation(), diag::err_deduction_guide_redeclared);
|
||||||
<< NewGuide->isExplicitSpecified();
|
|
||||||
Diag(Old->getLocation(), diag::note_previous_declaration);
|
Diag(Old->getLocation(), diag::note_previous_declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8638,12 +8637,12 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
|
||||||
R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
|
R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());
|
||||||
|
|
||||||
// C++0x explicit conversion operators.
|
// C++0x explicit conversion operators.
|
||||||
if (DS.isExplicitSpecified())
|
if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus2a)
|
||||||
Diag(DS.getExplicitSpecLoc(),
|
Diag(DS.getExplicitSpecLoc(),
|
||||||
getLangOpts().CPlusPlus11
|
getLangOpts().CPlusPlus11
|
||||||
? diag::warn_cxx98_compat_explicit_conversion_functions
|
? diag::warn_cxx98_compat_explicit_conversion_functions
|
||||||
: diag::ext_explicit_conversion_functions)
|
: diag::ext_explicit_conversion_functions)
|
||||||
<< SourceRange(DS.getExplicitSpecLoc());
|
<< SourceRange(DS.getExplicitSpecRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
|
/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
|
||||||
|
@ -10866,6 +10865,28 @@ struct ComputingExceptionSpec {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) {
|
||||||
|
llvm::APSInt Result;
|
||||||
|
ExprResult Converted = CheckConvertedConstantExpression(
|
||||||
|
ExplicitSpec.getExpr(), Context.BoolTy, Result, CCEK_ExplicitBool);
|
||||||
|
ExplicitSpec.setExpr(Converted.get());
|
||||||
|
if (Converted.isUsable() && !Converted.get()->isValueDependent()) {
|
||||||
|
ExplicitSpec.setKind(Result.getBoolValue()
|
||||||
|
? ExplicitSpecKind::ResolvedTrue
|
||||||
|
: ExplicitSpecKind::ResolvedFalse);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ExplicitSpec.setKind(ExplicitSpecKind::Unresolved);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExplicitSpecifier Sema::ActOnExplicitBoolSpecifier(Expr *ExplicitExpr) {
|
||||||
|
ExplicitSpecifier ES(ExplicitExpr, ExplicitSpecKind::Unresolved);
|
||||||
|
if (!ExplicitExpr->isTypeDependent())
|
||||||
|
tryResolveExplicitSpecifier(ES);
|
||||||
|
return ES;
|
||||||
|
}
|
||||||
|
|
||||||
static Sema::ImplicitExceptionSpecification
|
static Sema::ImplicitExceptionSpecification
|
||||||
ComputeDefaultedSpecialMemberExceptionSpec(
|
ComputeDefaultedSpecialMemberExceptionSpec(
|
||||||
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
|
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
|
||||||
|
@ -11014,9 +11035,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
|
||||||
= Context.DeclarationNames.getCXXConstructorName(ClassType);
|
= Context.DeclarationNames.getCXXConstructorName(ClassType);
|
||||||
DeclarationNameInfo NameInfo(Name, ClassLoc);
|
DeclarationNameInfo NameInfo(Name, ClassLoc);
|
||||||
CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
|
CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
|
||||||
Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(),
|
Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(),
|
||||||
/*TInfo=*/nullptr, /*isExplicit=*/false, /*isInline=*/true,
|
/*TInfo=*/nullptr, ExplicitSpecifier(),
|
||||||
/*isImplicitlyDeclared=*/true, Constexpr);
|
/*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr);
|
||||||
DefaultCon->setAccess(AS_public);
|
DefaultCon->setAccess(AS_public);
|
||||||
DefaultCon->setDefaulted();
|
DefaultCon->setDefaulted();
|
||||||
|
|
||||||
|
@ -11135,7 +11156,7 @@ Sema::findInheritingConstructor(SourceLocation Loc,
|
||||||
|
|
||||||
CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
|
CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
|
||||||
Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
|
Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
|
||||||
BaseCtor->isExplicit(), /*Inline=*/true,
|
BaseCtor->getExplicitSpecifier(), /*Inline=*/true,
|
||||||
/*ImplicitlyDeclared=*/true, Constexpr,
|
/*ImplicitlyDeclared=*/true, Constexpr,
|
||||||
InheritedConstructor(Shadow, BaseCtor));
|
InheritedConstructor(Shadow, BaseCtor));
|
||||||
if (Shadow->isInvalidDecl())
|
if (Shadow->isInvalidDecl())
|
||||||
|
@ -12588,8 +12609,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
|
||||||
// member of its class.
|
// member of its class.
|
||||||
CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
|
CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
|
||||||
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
|
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
|
||||||
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
|
ExplicitSpecifier(),
|
||||||
Constexpr);
|
/*isInline=*/true,
|
||||||
|
/*isImplicitlyDeclared=*/true, Constexpr);
|
||||||
CopyConstructor->setAccess(AS_public);
|
CopyConstructor->setAccess(AS_public);
|
||||||
CopyConstructor->setDefaulted();
|
CopyConstructor->setDefaulted();
|
||||||
|
|
||||||
|
@ -12718,8 +12740,9 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
|
||||||
// member of its class.
|
// member of its class.
|
||||||
CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
|
CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
|
||||||
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
|
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
|
||||||
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
|
ExplicitSpecifier(),
|
||||||
Constexpr);
|
/*isInline=*/true,
|
||||||
|
/*isImplicitlyDeclared=*/true, Constexpr);
|
||||||
MoveConstructor->setAccess(AS_public);
|
MoveConstructor->setAccess(AS_public);
|
||||||
MoveConstructor->setDefaulted();
|
MoveConstructor->setDefaulted();
|
||||||
|
|
||||||
|
|
|
@ -3763,9 +3763,10 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
|
||||||
hasCopyOrMoveCtorParam(S.Context, Info));
|
hasCopyOrMoveCtorParam(S.Context, Info));
|
||||||
|
|
||||||
if (Info.ConstructorTmpl)
|
if (Info.ConstructorTmpl)
|
||||||
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
|
S.AddTemplateOverloadCandidate(
|
||||||
/*ExplicitArgs*/ nullptr, Args,
|
Info.ConstructorTmpl, Info.FoundDecl,
|
||||||
CandidateSet, SuppressUserConversions);
|
/*ExplicitArgs*/ nullptr, Args, CandidateSet, SuppressUserConversions,
|
||||||
|
/*PartialOverloading=*/false, AllowExplicit);
|
||||||
else {
|
else {
|
||||||
// C++ [over.match.copy]p1:
|
// C++ [over.match.copy]p1:
|
||||||
// - When initializing a temporary to be bound to the first parameter
|
// - When initializing a temporary to be bound to the first parameter
|
||||||
|
@ -3779,8 +3780,8 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
|
||||||
hasCopyOrMoveCtorParam(S.Context, Info);
|
hasCopyOrMoveCtorParam(S.Context, Info);
|
||||||
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
|
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
|
||||||
CandidateSet, SuppressUserConversions,
|
CandidateSet, SuppressUserConversions,
|
||||||
/*PartialOverloading=*/false,
|
/*PartialOverloading=*/false, AllowExplicit,
|
||||||
/*AllowExplicit=*/AllowExplicitConv);
|
AllowExplicitConv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3813,16 +3814,17 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
|
||||||
else
|
else
|
||||||
Conv = cast<CXXConversionDecl>(D);
|
Conv = cast<CXXConversionDecl>(D);
|
||||||
|
|
||||||
if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
|
if (AllowExplicit || !Conv->isExplicit()) {
|
||||||
if (ConvTemplate)
|
if (ConvTemplate)
|
||||||
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
|
S.AddTemplateConversionCandidate(
|
||||||
ActingDC, Initializer, DestType,
|
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
|
||||||
CandidateSet, AllowExplicit,
|
CandidateSet, AllowExplicit, AllowExplicit,
|
||||||
/*AllowResultConversion*/false);
|
/*AllowResultConversion*/ false);
|
||||||
else
|
else
|
||||||
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
|
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
|
||||||
DestType, CandidateSet, AllowExplicit,
|
DestType, CandidateSet, AllowExplicit,
|
||||||
/*AllowResultConversion*/false);
|
AllowExplicit,
|
||||||
|
/*AllowResultConversion*/ false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4368,14 +4370,16 @@ static OverloadingResult TryRefInitWithConversionFunction(
|
||||||
if (!Info.Constructor->isInvalidDecl() &&
|
if (!Info.Constructor->isInvalidDecl() &&
|
||||||
Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
|
Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
|
||||||
if (Info.ConstructorTmpl)
|
if (Info.ConstructorTmpl)
|
||||||
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
|
S.AddTemplateOverloadCandidate(
|
||||||
/*ExplicitArgs*/ nullptr,
|
Info.ConstructorTmpl, Info.FoundDecl,
|
||||||
Initializer, CandidateSet,
|
/*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
|
||||||
/*SuppressUserConversions=*/true);
|
/*SuppressUserConversions=*/true,
|
||||||
|
/*PartialOverloading*/ false, AllowExplicitCtors);
|
||||||
else
|
else
|
||||||
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
|
S.AddOverloadCandidate(
|
||||||
Initializer, CandidateSet,
|
Info.Constructor, Info.FoundDecl, Initializer, CandidateSet,
|
||||||
/*SuppressUserConversions=*/true);
|
/*SuppressUserConversions=*/true,
|
||||||
|
/*PartialOverloading*/ false, AllowExplicitCtors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4410,17 +4414,17 @@ static OverloadingResult TryRefInitWithConversionFunction(
|
||||||
// candidates with reference-compatible results? That might be needed to
|
// candidates with reference-compatible results? That might be needed to
|
||||||
// break recursion.
|
// break recursion.
|
||||||
if ((AllowExplicitConvs || !Conv->isExplicit()) &&
|
if ((AllowExplicitConvs || !Conv->isExplicit()) &&
|
||||||
(AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
|
(AllowRValues ||
|
||||||
|
Conv->getConversionType()->isLValueReferenceType())) {
|
||||||
if (ConvTemplate)
|
if (ConvTemplate)
|
||||||
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
|
S.AddTemplateConversionCandidate(
|
||||||
ActingDC, Initializer,
|
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
|
||||||
DestType, CandidateSet,
|
CandidateSet,
|
||||||
/*AllowObjCConversionOnExplicit=*/
|
/*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
|
||||||
false);
|
|
||||||
else
|
else
|
||||||
S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
|
S.AddConversionCandidate(
|
||||||
Initializer, DestType, CandidateSet,
|
Conv, I.getPair(), ActingDC, Initializer, DestType, CandidateSet,
|
||||||
/*AllowObjCConversionOnExplicit=*/false);
|
/*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4996,14 +5000,16 @@ static void TryUserDefinedConversion(Sema &S,
|
||||||
if (!Info.Constructor->isInvalidDecl() &&
|
if (!Info.Constructor->isInvalidDecl() &&
|
||||||
Info.Constructor->isConvertingConstructor(AllowExplicit)) {
|
Info.Constructor->isConvertingConstructor(AllowExplicit)) {
|
||||||
if (Info.ConstructorTmpl)
|
if (Info.ConstructorTmpl)
|
||||||
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
|
S.AddTemplateOverloadCandidate(
|
||||||
/*ExplicitArgs*/ nullptr,
|
Info.ConstructorTmpl, Info.FoundDecl,
|
||||||
Initializer, CandidateSet,
|
/*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
|
||||||
/*SuppressUserConversions=*/true);
|
/*SuppressUserConversions=*/true,
|
||||||
|
/*PartialOverloading*/ false, AllowExplicit);
|
||||||
else
|
else
|
||||||
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
|
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
|
||||||
Initializer, CandidateSet,
|
Initializer, CandidateSet,
|
||||||
/*SuppressUserConversions=*/true);
|
/*SuppressUserConversions=*/true,
|
||||||
|
/*PartialOverloading*/ false, AllowExplicit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5038,12 +5044,12 @@ static void TryUserDefinedConversion(Sema &S,
|
||||||
|
|
||||||
if (AllowExplicit || !Conv->isExplicit()) {
|
if (AllowExplicit || !Conv->isExplicit()) {
|
||||||
if (ConvTemplate)
|
if (ConvTemplate)
|
||||||
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
|
S.AddTemplateConversionCandidate(
|
||||||
ActingDC, Initializer, DestType,
|
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
|
||||||
CandidateSet, AllowExplicit);
|
CandidateSet, AllowExplicit, AllowExplicit);
|
||||||
else
|
else
|
||||||
S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
|
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
|
||||||
Initializer, DestType, CandidateSet,
|
DestType, CandidateSet, AllowExplicit,
|
||||||
AllowExplicit);
|
AllowExplicit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9336,6 +9342,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
|
||||||
OverloadCandidateSet::iterator Best;
|
OverloadCandidateSet::iterator Best;
|
||||||
|
|
||||||
bool HasAnyDeductionGuide = false;
|
bool HasAnyDeductionGuide = false;
|
||||||
|
bool AllowExplicit = !Kind.isCopyInit() || ListInit;
|
||||||
|
|
||||||
auto tryToResolveOverload =
|
auto tryToResolveOverload =
|
||||||
[&](bool OnlyListConstructors) -> OverloadingResult {
|
[&](bool OnlyListConstructors) -> OverloadingResult {
|
||||||
|
@ -9361,7 +9368,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
|
||||||
// converting constructors (12.3.1) of that class.
|
// converting constructors (12.3.1) of that class.
|
||||||
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
|
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
|
||||||
// The converting constructors of T are candidate functions.
|
// The converting constructors of T are candidate functions.
|
||||||
if (Kind.isCopyInit() && !ListInit) {
|
if (!AllowExplicit) {
|
||||||
// Only consider converting constructors.
|
// Only consider converting constructors.
|
||||||
if (GD->isExplicit())
|
if (GD->isExplicit())
|
||||||
continue;
|
continue;
|
||||||
|
@ -9396,8 +9403,9 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
|
||||||
|
|
||||||
if (TD)
|
if (TD)
|
||||||
AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
|
AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
|
||||||
Inits, Candidates,
|
Inits, Candidates, SuppressUserConversions,
|
||||||
SuppressUserConversions);
|
/*PartialOverloading*/ false,
|
||||||
|
AllowExplicit);
|
||||||
else
|
else
|
||||||
AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
|
AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
|
||||||
SuppressUserConversions);
|
SuppressUserConversions);
|
||||||
|
|
|
@ -1306,7 +1306,7 @@ static void addFunctionPointerConversion(Sema &S,
|
||||||
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
|
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
|
||||||
S.Context, Class, Loc,
|
S.Context, Class, Loc,
|
||||||
DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
|
DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
|
||||||
/*isInline=*/true, /*isExplicit=*/false,
|
/*isInline=*/true, ExplicitSpecifier(),
|
||||||
/*isConstexpr=*/S.getLangOpts().CPlusPlus17,
|
/*isConstexpr=*/S.getLangOpts().CPlusPlus17,
|
||||||
CallOperator->getBody()->getEndLoc());
|
CallOperator->getBody()->getEndLoc());
|
||||||
Conversion->setAccess(AS_public);
|
Conversion->setAccess(AS_public);
|
||||||
|
@ -1393,7 +1393,7 @@ static void addBlockPointerConversion(Sema &S,
|
||||||
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
|
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
|
||||||
S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
|
S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
|
||||||
S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
|
S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
|
||||||
/*isInline=*/true, /*isExplicit=*/false,
|
/*isInline=*/true, ExplicitSpecifier(),
|
||||||
/*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
|
/*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
|
||||||
Conversion->setAccess(AS_public);
|
Conversion->setAccess(AS_public);
|
||||||
Conversion->setImplicit(true);
|
Conversion->setImplicit(true);
|
||||||
|
|
|
@ -3041,10 +3041,15 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
|
||||||
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
||||||
else if (CtorInfo)
|
else if (CtorInfo)
|
||||||
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
|
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
|
||||||
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
|
llvm::makeArrayRef(&Arg, NumArgs), OCS,
|
||||||
|
/*SuppressUserConversions*/ true,
|
||||||
|
/*PartialOverloading*/ false,
|
||||||
|
/*AllowExplcit*/ true);
|
||||||
else
|
else
|
||||||
AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
|
AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
|
||||||
true);
|
/*SuppressUserConversions*/ true,
|
||||||
|
/*PartialOverloading*/ false,
|
||||||
|
/*AllowExplcit*/ true);
|
||||||
} else if (FunctionTemplateDecl *Tmpl =
|
} else if (FunctionTemplateDecl *Tmpl =
|
||||||
dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
|
dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
|
||||||
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
|
||||||
|
|
|
@ -3242,10 +3242,13 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
|
||||||
if (Info.ConstructorTmpl)
|
if (Info.ConstructorTmpl)
|
||||||
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
|
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
|
||||||
/*ExplicitArgs*/ nullptr, From,
|
/*ExplicitArgs*/ nullptr, From,
|
||||||
CandidateSet, SuppressUserConversions);
|
CandidateSet, SuppressUserConversions,
|
||||||
|
/*PartialOverloading*/ false,
|
||||||
|
AllowExplicit);
|
||||||
else
|
else
|
||||||
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From,
|
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From,
|
||||||
CandidateSet, SuppressUserConversions);
|
CandidateSet, SuppressUserConversions,
|
||||||
|
/*PartialOverloading*/ false, AllowExplicit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3372,13 +3375,15 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
||||||
S.AddTemplateOverloadCandidate(
|
S.AddTemplateOverloadCandidate(
|
||||||
Info.ConstructorTmpl, Info.FoundDecl,
|
Info.ConstructorTmpl, Info.FoundDecl,
|
||||||
/*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
|
/*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
|
||||||
CandidateSet, SuppressUserConversions);
|
CandidateSet, SuppressUserConversions,
|
||||||
|
/*PartialOverloading*/ false, AllowExplicit);
|
||||||
else
|
else
|
||||||
// Allow one user-defined conversion when user specifies a
|
// Allow one user-defined conversion when user specifies a
|
||||||
// From->ToType conversion via an static cast (c-style, etc).
|
// From->ToType conversion via an static cast (c-style, etc).
|
||||||
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
|
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
|
||||||
llvm::makeArrayRef(Args, NumArgs),
|
llvm::makeArrayRef(Args, NumArgs),
|
||||||
CandidateSet, SuppressUserConversions);
|
CandidateSet, SuppressUserConversions,
|
||||||
|
/*PartialOverloading*/ false, AllowExplicit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3410,14 +3415,13 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
|
||||||
|
|
||||||
if (AllowExplicit || !Conv->isExplicit()) {
|
if (AllowExplicit || !Conv->isExplicit()) {
|
||||||
if (ConvTemplate)
|
if (ConvTemplate)
|
||||||
S.AddTemplateConversionCandidate(ConvTemplate, FoundDecl,
|
S.AddTemplateConversionCandidate(
|
||||||
ActingContext, From, ToType,
|
ConvTemplate, FoundDecl, ActingContext, From, ToType,
|
||||||
CandidateSet,
|
CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit);
|
||||||
AllowObjCConversionOnExplicit);
|
|
||||||
else
|
else
|
||||||
S.AddConversionCandidate(Conv, FoundDecl, ActingContext,
|
S.AddConversionCandidate(
|
||||||
From, ToType, CandidateSet,
|
Conv, FoundDecl, ActingContext, From, ToType, CandidateSet,
|
||||||
AllowObjCConversionOnExplicit);
|
AllowObjCConversionOnExplicit, AllowExplicit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4445,13 +4449,13 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ConvTemplate)
|
if (ConvTemplate)
|
||||||
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(), ActingDC,
|
S.AddTemplateConversionCandidate(
|
||||||
Init, DeclType, CandidateSet,
|
ConvTemplate, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
|
||||||
/*AllowObjCConversionOnExplicit=*/false);
|
/*AllowObjCConversionOnExplicit=*/false, AllowExplicit);
|
||||||
else
|
else
|
||||||
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Init,
|
S.AddConversionCandidate(
|
||||||
DeclType, CandidateSet,
|
Conv, I.getPair(), ActingDC, Init, DeclType, CandidateSet,
|
||||||
/*AllowObjCConversionOnExplicit=*/false);
|
/*AllowObjCConversionOnExplicit=*/false, AllowExplicit);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
bool HadMultipleCandidates = (CandidateSet.size() > 1);
|
||||||
|
@ -5414,7 +5418,7 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From,
|
||||||
// condition shall be a contextually converted constant expression of type
|
// condition shall be a contextually converted constant expression of type
|
||||||
// bool.
|
// bool.
|
||||||
ImplicitConversionSequence ICS =
|
ImplicitConversionSequence ICS =
|
||||||
CCE == Sema::CCEK_ConstexprIf
|
CCE == Sema::CCEK_ConstexprIf || CCE == Sema::CCEK_ExplicitBool
|
||||||
? TryContextuallyConvertToBool(S, From)
|
? TryContextuallyConvertToBool(S, From)
|
||||||
: TryCopyInitialization(S, From, T,
|
: TryCopyInitialization(S, From, T,
|
||||||
/*SuppressUserConversions=*/false,
|
/*SuppressUserConversions=*/false,
|
||||||
|
@ -5730,12 +5734,13 @@ collectViableConversionCandidates(Sema &SemaRef, Expr *From, QualType ToType,
|
||||||
|
|
||||||
if (ConvTemplate)
|
if (ConvTemplate)
|
||||||
SemaRef.AddTemplateConversionCandidate(
|
SemaRef.AddTemplateConversionCandidate(
|
||||||
ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
|
ConvTemplate, FoundDecl, ActingContext, From, ToType, CandidateSet,
|
||||||
/*AllowObjCConversionOnExplicit=*/false);
|
/*AllowObjCConversionOnExplicit=*/false, /*AllowExplicit*/ true);
|
||||||
else
|
else
|
||||||
SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,
|
SemaRef.AddConversionCandidate(Conv, FoundDecl, ActingContext, From,
|
||||||
ToType, CandidateSet,
|
ToType, CandidateSet,
|
||||||
/*AllowObjCConversionOnExplicit=*/false);
|
/*AllowObjCConversionOnExplicit=*/false,
|
||||||
|
/*AllowExplicit*/ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5987,13 +5992,11 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context,
|
||||||
/// \param PartialOverloading true if we are performing "partial" overloading
|
/// \param PartialOverloading true if we are performing "partial" overloading
|
||||||
/// based on an incomplete set of function arguments. This feature is used by
|
/// based on an incomplete set of function arguments. This feature is used by
|
||||||
/// code completion.
|
/// code completion.
|
||||||
void Sema::AddOverloadCandidate(FunctionDecl *Function,
|
void Sema::AddOverloadCandidate(
|
||||||
DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
|
FunctionDecl *Function, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet &CandidateSet,
|
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
|
||||||
bool SuppressUserConversions,
|
bool PartialOverloading, bool AllowExplicit, bool AllowExplicitConversions,
|
||||||
bool PartialOverloading, bool AllowExplicit,
|
ADLCallKind IsADLCandidate, ConversionSequenceList EarlyConversions) {
|
||||||
ADLCallKind IsADLCandidate,
|
|
||||||
ConversionSequenceList EarlyConversions) {
|
|
||||||
const FunctionProtoType *Proto
|
const FunctionProtoType *Proto
|
||||||
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
|
= dyn_cast<FunctionProtoType>(Function->getType()->getAs<FunctionType>());
|
||||||
assert(Proto && "Functions without a prototype cannot be overloaded");
|
assert(Proto && "Functions without a prototype cannot be overloaded");
|
||||||
|
@ -6150,13 +6153,11 @@ void Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||||
// (13.3.3.1) that converts that argument to the corresponding
|
// (13.3.3.1) that converts that argument to the corresponding
|
||||||
// parameter of F.
|
// parameter of F.
|
||||||
QualType ParamType = Proto->getParamType(ArgIdx);
|
QualType ParamType = Proto->getParamType(ArgIdx);
|
||||||
Candidate.Conversions[ArgIdx]
|
Candidate.Conversions[ArgIdx] = TryCopyInitialization(
|
||||||
= TryCopyInitialization(*this, Args[ArgIdx], ParamType,
|
*this, Args[ArgIdx], ParamType, SuppressUserConversions,
|
||||||
SuppressUserConversions,
|
/*InOverloadResolution=*/true,
|
||||||
/*InOverloadResolution=*/true,
|
/*AllowObjCWritebackConversion=*/
|
||||||
/*AllowObjCWritebackConversion=*/
|
getLangOpts().ObjCAutoRefCount, AllowExplicitConversions);
|
||||||
getLangOpts().ObjCAutoRefCount,
|
|
||||||
AllowExplicit);
|
|
||||||
if (Candidate.Conversions[ArgIdx].isBad()) {
|
if (Candidate.Conversions[ArgIdx].isBad()) {
|
||||||
Candidate.Viable = false;
|
Candidate.Viable = false;
|
||||||
Candidate.FailureKind = ovl_fail_bad_conversion;
|
Candidate.FailureKind = ovl_fail_bad_conversion;
|
||||||
|
@ -6170,6 +6171,15 @@ void Sema::AddOverloadCandidate(FunctionDecl *Function,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!AllowExplicit) {
|
||||||
|
ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function);
|
||||||
|
if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) {
|
||||||
|
Candidate.Viable = false;
|
||||||
|
Candidate.FailureKind = ovl_fail_explicit_resolved;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
|
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
|
||||||
Candidate.Viable = false;
|
Candidate.Viable = false;
|
||||||
Candidate.FailureKind = ovl_fail_enable_if;
|
Candidate.FailureKind = ovl_fail_enable_if;
|
||||||
|
@ -6759,7 +6769,7 @@ void Sema::AddTemplateOverloadCandidate(
|
||||||
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
|
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
|
||||||
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
|
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
|
||||||
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
|
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions,
|
||||||
bool PartialOverloading, ADLCallKind IsADLCandidate) {
|
bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate) {
|
||||||
if (!CandidateSet.isNewCandidate(FunctionTemplate))
|
if (!CandidateSet.isNewCandidate(FunctionTemplate))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -6808,9 +6818,10 @@ void Sema::AddTemplateOverloadCandidate(
|
||||||
// Add the function template specialization produced by template argument
|
// Add the function template specialization produced by template argument
|
||||||
// deduction as a candidate.
|
// deduction as a candidate.
|
||||||
assert(Specialization && "Missing function template specialization?");
|
assert(Specialization && "Missing function template specialization?");
|
||||||
AddOverloadCandidate(Specialization, FoundDecl, Args, CandidateSet,
|
AddOverloadCandidate(
|
||||||
SuppressUserConversions, PartialOverloading,
|
Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions,
|
||||||
/*AllowExplicit*/ false, IsADLCandidate, Conversions);
|
PartialOverloading, AllowExplicit,
|
||||||
|
/*AllowExplicitConversions*/ false, IsADLCandidate, Conversions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that implicit conversion sequences can be formed for each argument
|
/// Check that implicit conversion sequences can be formed for each argument
|
||||||
|
@ -6915,14 +6926,11 @@ static bool isAllowableExplicitConversion(Sema &S,
|
||||||
/// and ToType is the type that we're eventually trying to convert to
|
/// 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
|
/// (which may or may not be the same type as the type that the
|
||||||
/// conversion function produces).
|
/// conversion function produces).
|
||||||
void
|
void Sema::AddConversionCandidate(
|
||||||
Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
|
||||||
DeclAccessPair FoundDecl,
|
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
|
||||||
CXXRecordDecl *ActingContext,
|
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
|
||||||
Expr *From, QualType ToType,
|
bool AllowExplicit, bool AllowResultConversion) {
|
||||||
OverloadCandidateSet& CandidateSet,
|
|
||||||
bool AllowObjCConversionOnExplicit,
|
|
||||||
bool AllowResultConversion) {
|
|
||||||
assert(!Conversion->getDescribedFunctionTemplate() &&
|
assert(!Conversion->getDescribedFunctionTemplate() &&
|
||||||
"Conversion function templates use AddTemplateConversionCandidate");
|
"Conversion function templates use AddTemplateConversionCandidate");
|
||||||
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
|
QualType ConvType = Conversion->getConversionType().getNonReferenceType();
|
||||||
|
@ -7081,6 +7089,13 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
||||||
"Can only end up with a standard conversion sequence or failure");
|
"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)) {
|
if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
|
||||||
Candidate.Viable = false;
|
Candidate.Viable = false;
|
||||||
Candidate.FailureKind = ovl_fail_enable_if;
|
Candidate.FailureKind = ovl_fail_enable_if;
|
||||||
|
@ -7100,14 +7115,11 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion,
|
||||||
/// to deduce the template arguments of the conversion function
|
/// to deduce the template arguments of the conversion function
|
||||||
/// template from the type that we are converting to (C++
|
/// template from the type that we are converting to (C++
|
||||||
/// [temp.deduct.conv]).
|
/// [temp.deduct.conv]).
|
||||||
void
|
void Sema::AddTemplateConversionCandidate(
|
||||||
Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
|
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
|
||||||
DeclAccessPair FoundDecl,
|
CXXRecordDecl *ActingDC, Expr *From, QualType ToType,
|
||||||
CXXRecordDecl *ActingDC,
|
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
|
||||||
Expr *From, QualType ToType,
|
bool AllowExplicit, bool AllowResultConversion) {
|
||||||
OverloadCandidateSet &CandidateSet,
|
|
||||||
bool AllowObjCConversionOnExplicit,
|
|
||||||
bool AllowResultConversion) {
|
|
||||||
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
|
assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) &&
|
||||||
"Only conversion function templates permitted here");
|
"Only conversion function templates permitted here");
|
||||||
|
|
||||||
|
@ -7137,7 +7149,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
|
||||||
assert(Specialization && "Missing function template specialization?");
|
assert(Specialization && "Missing function template specialization?");
|
||||||
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
|
AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType,
|
||||||
CandidateSet, AllowObjCConversionOnExplicit,
|
CandidateSet, AllowObjCConversionOnExplicit,
|
||||||
AllowResultConversion);
|
AllowExplicit, AllowResultConversion);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
|
/// AddSurrogateCandidate - Adds a "surrogate" candidate function that
|
||||||
|
@ -8991,12 +9003,14 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
|
||||||
|
|
||||||
AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
|
AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet,
|
||||||
/*SupressUserConversions=*/false, PartialOverloading,
|
/*SupressUserConversions=*/false, PartialOverloading,
|
||||||
/*AllowExplicit=*/false, ADLCallKind::UsesADL);
|
/*AllowExplicitConversions*/ false,
|
||||||
|
/*AllowExplicit*/ false, ADLCallKind::UsesADL);
|
||||||
} else {
|
} else {
|
||||||
AddTemplateOverloadCandidate(cast<FunctionTemplateDecl>(*I), FoundDecl,
|
AddTemplateOverloadCandidate(
|
||||||
ExplicitTemplateArgs, Args, CandidateSet,
|
cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args,
|
||||||
/*SupressUserConversions=*/false,
|
CandidateSet,
|
||||||
PartialOverloading, ADLCallKind::UsesADL);
|
/*SupressUserConversions=*/false, PartialOverloading,
|
||||||
|
/*AllowExplicit*/ false, ADLCallKind::UsesADL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10327,6 +10341,33 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) {
|
||||||
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
<< Attr->getCond()->getSourceRange() << Attr->getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) {
|
||||||
|
ExplicitSpecifier ES;
|
||||||
|
const char *DeclName;
|
||||||
|
switch (Cand->Function->getDeclKind()) {
|
||||||
|
case Decl::Kind::CXXConstructor:
|
||||||
|
ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier();
|
||||||
|
DeclName = "constructor";
|
||||||
|
break;
|
||||||
|
case Decl::Kind::CXXConversion:
|
||||||
|
ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier();
|
||||||
|
DeclName = "conversion operator";
|
||||||
|
break;
|
||||||
|
case Decl::Kind::CXXDeductionGuide:
|
||||||
|
ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier();
|
||||||
|
DeclName = "deductiong guide";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
llvm_unreachable("invalid Decl");
|
||||||
|
}
|
||||||
|
assert(ES.getExpr() && "null expression should be handled before");
|
||||||
|
S.Diag(Cand->Function->getLocation(),
|
||||||
|
diag::note_ovl_candidate_explicit_forbidden)
|
||||||
|
<< DeclName;
|
||||||
|
S.Diag(ES.getExpr()->getBeginLoc(),
|
||||||
|
diag::note_explicit_bool_resolved_to_true);
|
||||||
|
}
|
||||||
|
|
||||||
static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
|
static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) {
|
||||||
FunctionDecl *Callee = Cand->Function;
|
FunctionDecl *Callee = Cand->Function;
|
||||||
|
|
||||||
|
@ -10411,6 +10452,9 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
|
||||||
case ovl_fail_enable_if:
|
case ovl_fail_enable_if:
|
||||||
return DiagnoseFailedEnableIfAttr(S, Cand);
|
return DiagnoseFailedEnableIfAttr(S, Cand);
|
||||||
|
|
||||||
|
case ovl_fail_explicit_resolved:
|
||||||
|
return DiagnoseFailedExplicitSpec(S, Cand);
|
||||||
|
|
||||||
case ovl_fail_ext_disabled:
|
case ovl_fail_ext_disabled:
|
||||||
return DiagnoseOpenCLExtensionDisabled(S, Cand);
|
return DiagnoseOpenCLExtensionDisabled(S, Cand);
|
||||||
|
|
||||||
|
@ -12981,8 +13025,11 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
||||||
|
|
||||||
// Microsoft supports direct constructor calls.
|
// Microsoft supports direct constructor calls.
|
||||||
if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
|
if (getLangOpts().MicrosoftExt && isa<CXXConstructorDecl>(Func)) {
|
||||||
AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(),
|
AddOverloadCandidate(cast<CXXConstructorDecl>(Func), I.getPair(), Args,
|
||||||
Args, CandidateSet);
|
CandidateSet,
|
||||||
|
/*SuppressUserConversions*/ false,
|
||||||
|
/*PartialOverloading*/ false,
|
||||||
|
/*AllowExplicit*/ true);
|
||||||
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
|
} else if ((Method = dyn_cast<CXXMethodDecl>(Func))) {
|
||||||
// If explicit template arguments were provided, we can't call a
|
// If explicit template arguments were provided, we can't call a
|
||||||
// non-template member function.
|
// non-template member function.
|
||||||
|
|
|
@ -1109,7 +1109,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
|
||||||
if (DS.isVirtualSpecified())
|
if (DS.isVirtualSpecified())
|
||||||
EmitDiag(DS.getVirtualSpecLoc());
|
EmitDiag(DS.getVirtualSpecLoc());
|
||||||
|
|
||||||
if (DS.isExplicitSpecified())
|
if (DS.hasExplicitSpecifier())
|
||||||
EmitDiag(DS.getExplicitSpecLoc());
|
EmitDiag(DS.getExplicitSpecLoc());
|
||||||
|
|
||||||
if (DS.isNoreturnSpecified())
|
if (DS.isNoreturnSpecified())
|
||||||
|
@ -1789,8 +1789,8 @@ struct ConvertConstructorToDeductionGuideTransform {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
|
TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);
|
||||||
|
|
||||||
return buildDeductionGuide(TemplateParams, CD->isExplicit(), NewTInfo,
|
return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(),
|
||||||
CD->getBeginLoc(), CD->getLocation(),
|
NewTInfo, CD->getBeginLoc(), CD->getLocation(),
|
||||||
CD->getEndLoc());
|
CD->getEndLoc());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1819,8 +1819,8 @@ struct ConvertConstructorToDeductionGuideTransform {
|
||||||
Params.push_back(NewParam);
|
Params.push_back(NewParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildDeductionGuide(Template->getTemplateParameters(), false, TSI,
|
return buildDeductionGuide(Template->getTemplateParameters(),
|
||||||
Loc, Loc, Loc);
|
ExplicitSpecifier(), TSI, Loc, Loc, Loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -1970,7 +1970,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
|
NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
|
||||||
bool Explicit, TypeSourceInfo *TInfo,
|
ExplicitSpecifier ES, TypeSourceInfo *TInfo,
|
||||||
SourceLocation LocStart, SourceLocation Loc,
|
SourceLocation LocStart, SourceLocation Loc,
|
||||||
SourceLocation LocEnd) {
|
SourceLocation LocEnd) {
|
||||||
DeclarationNameInfo Name(DeductionGuideName, Loc);
|
DeclarationNameInfo Name(DeductionGuideName, Loc);
|
||||||
|
@ -1979,8 +1979,8 @@ private:
|
||||||
|
|
||||||
// Build the implicit deduction guide template.
|
// Build the implicit deduction guide template.
|
||||||
auto *Guide =
|
auto *Guide =
|
||||||
CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit,
|
CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name,
|
||||||
Name, TInfo->getType(), TInfo, LocEnd);
|
TInfo->getType(), TInfo, LocEnd);
|
||||||
Guide->setImplicit();
|
Guide->setImplicit();
|
||||||
Guide->setParams(Params);
|
Guide->setParams(Params);
|
||||||
|
|
||||||
|
|
|
@ -366,6 +366,29 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
|
||||||
Attr.getSpellingListIndex());
|
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(
|
static void instantiateDependentAMDGPUWavesPerEUAttr(
|
||||||
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
|
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||||
const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
|
const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
|
||||||
|
@ -1690,6 +1713,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
|
||||||
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
|
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
|
||||||
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
|
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);
|
||||||
|
|
||||||
|
ExplicitSpecifier InstantiatedExplicitSpecifier;
|
||||||
|
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
|
||||||
|
InstantiatedExplicitSpecifier = instantiateExplicitSpecifier(
|
||||||
|
SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide);
|
||||||
|
if (InstantiatedExplicitSpecifier.isInvalid())
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
SmallVector<ParmVarDecl *, 4> Params;
|
SmallVector<ParmVarDecl *, 4> Params;
|
||||||
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
|
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
|
||||||
if (!TInfo)
|
if (!TInfo)
|
||||||
|
@ -1727,8 +1758,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
|
||||||
FunctionDecl *Function;
|
FunctionDecl *Function;
|
||||||
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
|
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
|
||||||
Function = CXXDeductionGuideDecl::Create(
|
Function = CXXDeductionGuideDecl::Create(
|
||||||
SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
|
SemaRef.Context, DC, D->getInnerLocStart(),
|
||||||
NameInfo, T, TInfo, D->getSourceRange().getEnd());
|
InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
|
||||||
|
D->getSourceRange().getEnd());
|
||||||
if (DGuide->isCopyDeductionCandidate())
|
if (DGuide->isCopyDeductionCandidate())
|
||||||
cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
|
cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
|
||||||
Function->setAccess(D->getAccess());
|
Function->setAccess(D->getAccess());
|
||||||
|
@ -1996,6 +2028,12 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExplicitSpecifier InstantiatedExplicitSpecifier =
|
||||||
|
instantiateExplicitSpecifier(SemaRef, TemplateArgs,
|
||||||
|
ExplicitSpecifier::getFromDecl(D), D);
|
||||||
|
if (InstantiatedExplicitSpecifier.isInvalid())
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
SmallVector<ParmVarDecl *, 4> Params;
|
SmallVector<ParmVarDecl *, 4> Params;
|
||||||
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
|
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
|
||||||
if (!TInfo)
|
if (!TInfo)
|
||||||
|
@ -2035,11 +2073,10 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||||
DeclarationNameInfo NameInfo
|
DeclarationNameInfo NameInfo
|
||||||
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
|
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
|
||||||
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
|
||||||
Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
|
Method = CXXConstructorDecl::Create(
|
||||||
StartLoc, NameInfo, T, TInfo,
|
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
|
||||||
Constructor->isExplicit(),
|
InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false,
|
||||||
Constructor->isInlineSpecified(),
|
Constructor->isConstexpr());
|
||||||
false, Constructor->isConstexpr());
|
|
||||||
Method->setRangeEnd(Constructor->getEndLoc());
|
Method->setRangeEnd(Constructor->getEndLoc());
|
||||||
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
|
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
|
||||||
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
|
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
|
||||||
|
@ -2050,7 +2087,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
|
||||||
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
|
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
|
||||||
Method = CXXConversionDecl::Create(
|
Method = CXXConversionDecl::Create(
|
||||||
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
|
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
|
||||||
Conversion->isInlineSpecified(), Conversion->isExplicit(),
|
Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
|
||||||
Conversion->isConstexpr(), Conversion->getEndLoc());
|
Conversion->isConstexpr(), Conversion->getEndLoc());
|
||||||
} else {
|
} else {
|
||||||
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
|
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
|
||||||
|
|
|
@ -858,7 +858,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
|
||||||
FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
|
FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
|
||||||
FD->setInlineSpecified(Record.readInt());
|
FD->setInlineSpecified(Record.readInt());
|
||||||
FD->setImplicitlyInline(Record.readInt());
|
FD->setImplicitlyInline(Record.readInt());
|
||||||
FD->setExplicitSpecified(Record.readInt());
|
|
||||||
FD->setVirtualAsWritten(Record.readInt());
|
FD->setVirtualAsWritten(Record.readInt());
|
||||||
FD->setPure(Record.readInt());
|
FD->setPure(Record.readInt());
|
||||||
FD->setHasInheritedPrototype(Record.readInt());
|
FD->setHasInheritedPrototype(Record.readInt());
|
||||||
|
@ -1977,6 +1976,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
|
void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
|
||||||
|
D->setExplicitSpecifier(Record.readExplicitSpec());
|
||||||
VisitFunctionDecl(D);
|
VisitFunctionDecl(D);
|
||||||
D->setIsCopyDeductionCandidate(Record.readInt());
|
D->setIsCopyDeductionCandidate(Record.readInt());
|
||||||
}
|
}
|
||||||
|
@ -2002,6 +2002,7 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
||||||
void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
|
void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
|
||||||
// We need the inherited constructor information to merge the declaration,
|
// We need the inherited constructor information to merge the declaration,
|
||||||
// so we have to read it before we call VisitCXXMethodDecl.
|
// so we have to read it before we call VisitCXXMethodDecl.
|
||||||
|
D->setExplicitSpecifier(Record.readExplicitSpec());
|
||||||
if (D->isInheritingConstructor()) {
|
if (D->isInheritingConstructor()) {
|
||||||
auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>();
|
auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>();
|
||||||
auto *Ctor = ReadDeclAs<CXXConstructorDecl>();
|
auto *Ctor = ReadDeclAs<CXXConstructorDecl>();
|
||||||
|
@ -2027,6 +2028,7 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
|
void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
|
||||||
|
D->setExplicitSpecifier(Record.readExplicitSpec());
|
||||||
VisitCXXMethodDecl(D);
|
VisitCXXMethodDecl(D);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3750,10 +3752,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
||||||
D = CXXMethodDecl::CreateDeserialized(Context, ID);
|
D = CXXMethodDecl::CreateDeserialized(Context, ID);
|
||||||
break;
|
break;
|
||||||
case DECL_CXX_CONSTRUCTOR:
|
case DECL_CXX_CONSTRUCTOR:
|
||||||
D = CXXConstructorDecl::CreateDeserialized(Context, ID, false);
|
D = CXXConstructorDecl::CreateDeserialized(Context, ID, Record.readInt());
|
||||||
break;
|
|
||||||
case DECL_CXX_INHERITED_CONSTRUCTOR:
|
|
||||||
D = CXXConstructorDecl::CreateDeserialized(Context, ID, true);
|
|
||||||
break;
|
break;
|
||||||
case DECL_CXX_DESTRUCTOR:
|
case DECL_CXX_DESTRUCTOR:
|
||||||
D = CXXDestructorDecl::CreateDeserialized(Context, ID);
|
D = CXXDestructorDecl::CreateDeserialized(Context, ID);
|
||||||
|
|
|
@ -1266,7 +1266,6 @@ void ASTWriter::WriteBlockInfoBlock() {
|
||||||
RECORD(DECL_CXX_RECORD);
|
RECORD(DECL_CXX_RECORD);
|
||||||
RECORD(DECL_CXX_METHOD);
|
RECORD(DECL_CXX_METHOD);
|
||||||
RECORD(DECL_CXX_CONSTRUCTOR);
|
RECORD(DECL_CXX_CONSTRUCTOR);
|
||||||
RECORD(DECL_CXX_INHERITED_CONSTRUCTOR);
|
|
||||||
RECORD(DECL_CXX_DESTRUCTOR);
|
RECORD(DECL_CXX_DESTRUCTOR);
|
||||||
RECORD(DECL_CXX_CONVERSION);
|
RECORD(DECL_CXX_CONVERSION);
|
||||||
RECORD(DECL_ACCESS_SPEC);
|
RECORD(DECL_ACCESS_SPEC);
|
||||||
|
|
|
@ -535,7 +535,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
Record.push_back(static_cast<int>(D->getStorageClass())); // FIXME: stable encoding
|
Record.push_back(static_cast<int>(D->getStorageClass())); // FIXME: stable encoding
|
||||||
Record.push_back(D->isInlineSpecified());
|
Record.push_back(D->isInlineSpecified());
|
||||||
Record.push_back(D->isInlined());
|
Record.push_back(D->isInlined());
|
||||||
Record.push_back(D->isExplicitSpecified());
|
|
||||||
Record.push_back(D->isVirtualAsWritten());
|
Record.push_back(D->isVirtualAsWritten());
|
||||||
Record.push_back(D->isPure());
|
Record.push_back(D->isPure());
|
||||||
Record.push_back(D->hasInheritedPrototype());
|
Record.push_back(D->hasInheritedPrototype());
|
||||||
|
@ -638,7 +637,18 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
|
||||||
Code = serialization::DECL_FUNCTION;
|
Code = serialization::DECL_FUNCTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void addExplicitSpecifier(ExplicitSpecifier ES,
|
||||||
|
ASTRecordWriter &Record) {
|
||||||
|
uint64_t Kind = static_cast<uint64_t>(ES.getKind());
|
||||||
|
Kind = Kind << 1 | static_cast<bool>(ES.getExpr());
|
||||||
|
Record.push_back(Kind);
|
||||||
|
if (ES.getExpr()) {
|
||||||
|
Record.AddStmt(ES.getExpr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
|
void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
|
||||||
|
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
|
||||||
VisitFunctionDecl(D);
|
VisitFunctionDecl(D);
|
||||||
Record.push_back(D->isCopyDeductionCandidate());
|
Record.push_back(D->isCopyDeductionCandidate());
|
||||||
Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
|
Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
|
||||||
|
@ -1331,19 +1341,15 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
|
void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
|
||||||
|
Record.push_back(D->getTraillingAllocKind());
|
||||||
|
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
|
||||||
if (auto Inherited = D->getInheritedConstructor()) {
|
if (auto Inherited = D->getInheritedConstructor()) {
|
||||||
Record.AddDeclRef(Inherited.getShadowDecl());
|
Record.AddDeclRef(Inherited.getShadowDecl());
|
||||||
Record.AddDeclRef(Inherited.getConstructor());
|
Record.AddDeclRef(Inherited.getConstructor());
|
||||||
Code = serialization::DECL_CXX_INHERITED_CONSTRUCTOR;
|
|
||||||
} else {
|
|
||||||
Code = serialization::DECL_CXX_CONSTRUCTOR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VisitCXXMethodDecl(D);
|
VisitCXXMethodDecl(D);
|
||||||
|
Code = serialization::DECL_CXX_CONSTRUCTOR;
|
||||||
Code = D->isInheritingConstructor()
|
|
||||||
? serialization::DECL_CXX_INHERITED_CONSTRUCTOR
|
|
||||||
: serialization::DECL_CXX_CONSTRUCTOR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
||||||
|
@ -1357,6 +1363,7 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
|
void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
|
||||||
|
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
|
||||||
VisitCXXMethodDecl(D);
|
VisitCXXMethodDecl(D);
|
||||||
Code = serialization::DECL_CXX_CONVERSION;
|
Code = serialization::DECL_CXX_CONVERSION;
|
||||||
}
|
}
|
||||||
|
@ -2156,7 +2163,6 @@ void ASTWriter::WriteDeclAbbrevs() {
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified
|
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)); // VirtualAsWritten
|
||||||
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
|
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
|
||||||
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto
|
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto
|
||||||
|
|
|
@ -71,7 +71,7 @@ extern A(int(&)[26]) -> A<int>;
|
||||||
#endif
|
#endif
|
||||||
mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}}
|
mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}}
|
||||||
virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}}
|
virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}}
|
||||||
const A(int(&)[28]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}}
|
const A(int(&)[31]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}}
|
||||||
|
|
||||||
const volatile static constexpr inline A(int(&)[29]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static inline constexpr const volatile'}}
|
const volatile static constexpr inline A(int(&)[29]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static inline constexpr const volatile'}}
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
// The same restrictions apply to the parameter-declaration-clause of a
|
// The same restrictions apply to the parameter-declaration-clause of a
|
||||||
// deduction guide as in a function declaration.
|
// deduction guide as in a function declaration.
|
||||||
template<typename T> struct A {};
|
template<typename T> struct A {};
|
||||||
A(void) -> A<int>; // ok
|
A(void) -> A<int>; // expected-note {{previous}}
|
||||||
A(void, int) -> A<int>; // expected-error {{'void' must be the first and only parameter if specified}}
|
A(void, int) -> A<int>; // expected-error {{'void' must be the first and only parameter if specified}}
|
||||||
|
|
||||||
// We interpret this as also extending to the validity of redeclarations. It's
|
A() -> A<int>; // expected-error {{redeclaration of deduction guide}}
|
||||||
// a bit of a stretch (OK, a lot of a stretch) but it gives desirable answers.
|
// expected-note@-1 {{previous}}
|
||||||
A() -> A<int>; // ok, redeclaration
|
|
||||||
|
|
||||||
A() -> A<int>; // expected-note {{previous}}
|
A() -> A<int>; // expected-note {{previous}}
|
||||||
|
// expected-error@-1 {{redeclaration of deduction guide}}
|
||||||
A() -> A<float>; // FIXME: "functions" is a poor term. expected-error {{functions that differ only in their return type cannot be overloaded}}
|
A() -> A<float>; // FIXME: "functions" is a poor term. expected-error {{functions that differ only in their return type cannot be overloaded}}
|
||||||
|
|
||||||
template<typename T> A(T) -> A<typename T::foo>;
|
template<typename T> A(T) -> A<typename T::foo>;
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++2a -emit-pch %s -o %t-cxx2a
|
||||||
|
// RUN: %clang_cc1 -std=c++2a -DUSE_PCH -include-pch %t-cxx2a %s -ast-print -verify | FileCheck %s
|
||||||
|
|
||||||
|
#ifndef USE_PCH
|
||||||
|
namespace inheriting_constructor {
|
||||||
|
struct S {};
|
||||||
|
|
||||||
|
template<typename X, typename Y> struct T {
|
||||||
|
template<typename A>
|
||||||
|
explicit((Y{}, true)) T(A &&a) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename X, typename Y> struct U : T<X, Y> {
|
||||||
|
using T<X, Y>::T;
|
||||||
|
};
|
||||||
|
|
||||||
|
U<S, char> foo(char ch) {
|
||||||
|
return U<S, char>(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
namespace inheriting_constructor {
|
||||||
|
U<S, char> a = foo('0');
|
||||||
|
}
|
||||||
|
|
||||||
|
//CHECK: explicit((char{} , true))
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace basic {
|
||||||
|
#ifndef USE_PCH
|
||||||
|
|
||||||
|
struct B {};
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
explicit A(int);
|
||||||
|
explicit(false) operator bool();
|
||||||
|
explicit(true) operator B();
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
//expected-note@-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<bool b>
|
||||||
|
struct B {
|
||||||
|
static constexpr bool value = b;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
struct A {
|
||||||
|
explicit(b) A(B<b>) {}
|
||||||
|
template<typename T>
|
||||||
|
explicit(b ^ T::value) operator T();
|
||||||
|
};
|
||||||
|
B<true> b_true;
|
||||||
|
B<false> b_false;
|
||||||
|
#else
|
||||||
|
//expected-note@-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<true> b = a_true;
|
||||||
|
B<true> b1 = a_false; //expected-error {{no viable conversion}}
|
||||||
|
B<false> b2(a_true);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace guide {
|
||||||
|
|
||||||
|
#ifndef USE_PCH
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct A {
|
||||||
|
A(T);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
explicit(true) A(T) -> A<T>;
|
||||||
|
|
||||||
|
explicit(false) A(int) -> A<int>;
|
||||||
|
|
||||||
|
#else
|
||||||
|
//expected-note@-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
|
||||||
|
|
||||||
|
}
|
|
@ -115,7 +115,7 @@ static_assert(&r == &x);
|
||||||
|
|
||||||
#if defined(__cpp_conditional_explicit)
|
#if defined(__cpp_conditional_explicit)
|
||||||
struct TestConditionalExplicit {
|
struct TestConditionalExplicit {
|
||||||
explicit(__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
|
explicit(!__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
|
||||||
};
|
};
|
||||||
TestConditionalExplicit e = 42;
|
TestConditionalExplicit e = 42;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,3 +37,23 @@ string u8str = u8"test" u8"test";
|
||||||
// expected-error@-8 {{cannot initialize a variable of type 'const char *' with an lvalue of type 'const char8_t [6]'}}
|
// 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'}}
|
// expected-error@-8 {{no viable conversion from 'const char8_t [9]' to 'string'}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
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
|
|
@ -0,0 +1,719 @@
|
||||||
|
// RUN: %clang_cc1 -std=c++2a -fsyntax-only %s -verify
|
||||||
|
|
||||||
|
template <bool b, auto val> struct enable_ifv {};
|
||||||
|
|
||||||
|
template <auto val> struct enable_ifv<true, val> {
|
||||||
|
static constexpr auto value = val;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T1, typename T2> struct is_same {
|
||||||
|
static constexpr bool value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct is_same<T, T> {
|
||||||
|
static constexpr bool value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace special_cases
|
||||||
|
{
|
||||||
|
|
||||||
|
template<int a>
|
||||||
|
struct A {
|
||||||
|
// expected-note@-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<int a>
|
||||||
|
struct B {
|
||||||
|
explicit(b)
|
||||||
|
// expected-error@-1 {{use of undeclared identifier}}
|
||||||
|
B(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<int a>
|
||||||
|
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<int a>
|
||||||
|
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 <typename T> struct E {
|
||||||
|
// expected-note@-1+ {{candidate constructor}}
|
||||||
|
explicit((T{}, false))
|
||||||
|
// expected-error@-1 {{illegal initializer type 'void'}}
|
||||||
|
E(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
E<void> e = 1;
|
||||||
|
// expected-error@-1 {{no viable conversion}}
|
||||||
|
// expected-note@-2 {{in instantiation of}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace trailling_object {
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
struct B {
|
||||||
|
explicit(b) B(int) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
struct A : B<b> {
|
||||||
|
explicit(b) A(int) : B<b>(0) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
A<true> a(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace constructor1 {
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
struct A {
|
||||||
|
// expected-note@-1+ {{candidate constructor}}
|
||||||
|
// expected-note@-2+ {{candidate function}}
|
||||||
|
explicit(b) A(int, int = 0);
|
||||||
|
// expected-note@-1+ {{explicit constructor declared here}}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
A<b>::A(int, int) {}
|
||||||
|
|
||||||
|
void f()
|
||||||
|
{
|
||||||
|
A<true> a0 = 0; // expected-error {{no viable conversion}}
|
||||||
|
A<true> a1( 0);
|
||||||
|
A<true> && a2 = 0;// expected-error {{could not bind}}
|
||||||
|
A<true> && a3( 0);// expected-error {{could not bind}}
|
||||||
|
A<true> a4{ 0};
|
||||||
|
A<true> && a5 = { 0};// expected-error {{chosen constructor is explicit}}
|
||||||
|
A<true> && a6{ 0};
|
||||||
|
A<true> a7 = { 0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
|
||||||
|
|
||||||
|
a0 = 0;
|
||||||
|
a1 = { 0}; // expected-error {{no viable overloaded '='}}
|
||||||
|
a2 = A<true>( 0);
|
||||||
|
a3 = A<true>{ 0};
|
||||||
|
|
||||||
|
A<false> c0 = ((short)0);
|
||||||
|
A<false> c1( ((short)0));
|
||||||
|
A<false> && c2 = ((short)0);
|
||||||
|
A<false> && c3( ((short)0));
|
||||||
|
A<false> c4{ ((short)0)};
|
||||||
|
A<false> && c5 = { ((short)0)};
|
||||||
|
A<false> && c6{ ((short)0)};
|
||||||
|
|
||||||
|
A<true> d1( 0, 0);
|
||||||
|
A<true> d2{ 0, 0};
|
||||||
|
A<true> d3 = { 0, 0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
|
||||||
|
|
||||||
|
d1 = { 0, 0}; // expected-error {{no viable overloaded '='}}
|
||||||
|
d2 = A<true>( 0, 0);
|
||||||
|
d3 = A<true>{ 0, 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace constructor2 {
|
||||||
|
|
||||||
|
template<bool a, typename T1>
|
||||||
|
struct A {
|
||||||
|
// expected-note@-1 {{candidate constructor}} expected-note@-1 {{candidate constructor}}
|
||||||
|
// expected-note@-2 {{candidate constructor}} expected-note@-2 {{candidate constructor}}
|
||||||
|
template<typename T2>
|
||||||
|
explicit(a ^ is_same<T1, T2>::value)
|
||||||
|
// expected-note@-1+ {{explicit(bool) specifier resolved to true}}
|
||||||
|
A(T2) {}
|
||||||
|
// expected-note@-1+ {{explicit constructor declared here}}
|
||||||
|
// expected-note@-2+ {{candidate constructor ignored}}
|
||||||
|
};
|
||||||
|
|
||||||
|
A<true, int> a0 = 0.0; // expected-error {{no viable conversion}}
|
||||||
|
A<true, int> a1( 0.0);
|
||||||
|
A<true, int> && a2 = 0.0;// expected-error {{could not bind}}
|
||||||
|
A<true, int> && a3( 0.0);// expected-error {{could not bind}}
|
||||||
|
A<true, int> a4{ 0.0};
|
||||||
|
A<true, int> && a5 = { 0.0};// expected-error {{chosen constructor is explicit}}
|
||||||
|
A<true, int> && a6{ 0.0};
|
||||||
|
A<true, int> a7 = { 0.0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
|
||||||
|
|
||||||
|
A<true, int> b0 = 0;
|
||||||
|
A<true, int> b1( 0);
|
||||||
|
A<true, int> && b2 = 0;
|
||||||
|
A<true, int> && b3( 0);
|
||||||
|
A<true, int> b4{ 0};
|
||||||
|
A<true, int> && b5 = { 0};
|
||||||
|
A<true, int> && b6{ 0};
|
||||||
|
A<true, int> b7 = { 0};
|
||||||
|
|
||||||
|
A<true, double> c0 = 0; // expected-error {{no viable conversion}}
|
||||||
|
A<true, double> c1( 0);
|
||||||
|
A<true, double> && c2 = 0;// expected-error {{could not bind}}
|
||||||
|
A<true, double> && c3( 0);// expected-error {{could not bind}}
|
||||||
|
A<true, double> c4{ 0};
|
||||||
|
A<true, double> && c5 = { 0};// expected-error {{chosen constructor is explicit}}
|
||||||
|
A<true, double> && c6{ 0};
|
||||||
|
A<true, double> c7 = { 0}; // expected-error {{chosen constructor is explicit in copy-initialization}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace constructor_sfinae {
|
||||||
|
|
||||||
|
template<bool a>
|
||||||
|
struct A {
|
||||||
|
// expected-note@-1+ {{candidate constructor}}
|
||||||
|
template<typename T>
|
||||||
|
explicit(enable_ifv<is_same<int, T>::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<typename T, bool c = true>
|
||||||
|
explicit(enable_ifv<is_same<bool, T>::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<true> a0 = 0.0; // expected-error {{no viable conversion}}
|
||||||
|
A<true> a1( 0.0); // expected-error {{no matching constructor}}
|
||||||
|
A<true> a4{ 0.0}; // expected-error {{no matching constructor}}
|
||||||
|
A<true> a7 = { 0.0}; // expected-error {{no matching constructor}}
|
||||||
|
|
||||||
|
A<true> b0 = 0; // expected-error {{no viable conversion}}
|
||||||
|
A<true> b1( 0);
|
||||||
|
A<true> b4{ 0};
|
||||||
|
A<true> b7 = { 0}; // expected-error {{chosen constructor is explicit}}
|
||||||
|
|
||||||
|
A<false> c0 = 0;
|
||||||
|
A<false> c1( 0);
|
||||||
|
A<false> c4{ 0};
|
||||||
|
A<false> c7 = { 0};
|
||||||
|
|
||||||
|
A<true> d0 = true; // expected-error {{no viable conversion}}
|
||||||
|
A<true> d1( true);
|
||||||
|
A<true> d4{ true};
|
||||||
|
A<true> d7 = { true}; // expected-error {{chosen constructor is explicit}}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace conversion {
|
||||||
|
|
||||||
|
template<bool a>
|
||||||
|
struct A {
|
||||||
|
explicit(a) operator int ();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool a>
|
||||||
|
A<a>::operator int() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
A<true> A_true;
|
||||||
|
A<false> A_false;
|
||||||
|
|
||||||
|
int ai0 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
const int& ai1 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
int&& ai3 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
int ai4 = A_true; // expected-error {{no viable conversion}}
|
||||||
|
const int& ai5 = A_true; // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
|
int ai01 = {A<true>()}; // expected-error {{no viable conversion}}
|
||||||
|
const int& ai11 = {A<true>()}; // expected-error {{no viable conversion}}
|
||||||
|
int&& ai31 = {A<true>()}; // expected-error {{no viable conversion}}
|
||||||
|
int ai41 = {A_true}; // expected-error {{no viable conversion}}
|
||||||
|
const int& ai51 = {A_true}; // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
|
int ae0(A<true>());
|
||||||
|
const int& ae1(A<true>());
|
||||||
|
int&& ae3(A<true>());
|
||||||
|
int ae4(A_true);
|
||||||
|
const int& ae5(A_true);
|
||||||
|
|
||||||
|
int bi0 = A<false>();
|
||||||
|
const int& bi1 = A<false>();
|
||||||
|
int&& bi3 = A<false>();
|
||||||
|
int bi4 = A_false;
|
||||||
|
const int& bi5 = A_false;
|
||||||
|
|
||||||
|
int bi01 = {A<false>()};
|
||||||
|
const int& bi11 = {A<false>()};
|
||||||
|
int&& bi31 = {A<false>()};
|
||||||
|
int bi41 = {A_false};
|
||||||
|
const int& bi51 = {A_false};
|
||||||
|
|
||||||
|
int be0(A<true>());
|
||||||
|
const int& be1(A<true>());
|
||||||
|
int&& be3(A<true>());
|
||||||
|
int be4(A_true);
|
||||||
|
const int& be5(A_true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace conversion2 {
|
||||||
|
|
||||||
|
struct B {};
|
||||||
|
// expected-note@-1+ {{candidate constructor}}
|
||||||
|
template<bool a>
|
||||||
|
struct A {
|
||||||
|
template<typename T2>
|
||||||
|
explicit(enable_ifv<is_same<B, T2>::value, a>::value)
|
||||||
|
// expected-note@-1+ {{explicit(bool) specifier resolved to true}}
|
||||||
|
operator T2() { return T2(); };
|
||||||
|
// expected-note@-1+ {{substitution failure}}
|
||||||
|
// expected-note@-2+ {{candidate conversion}}
|
||||||
|
};
|
||||||
|
|
||||||
|
A<false> A_false;
|
||||||
|
A<true> A_true;
|
||||||
|
|
||||||
|
int ai0 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
const int& ai1 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
int&& ai3 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
int ai4 = A_false; // expected-error {{no viable conversion}}
|
||||||
|
const int& ai5 = A_false; // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
|
int ae0{A<true>()}; // expected-error {{no viable conversion}}
|
||||||
|
const int& ae1{A<true>()}; // expected-error {{no viable conversion}}
|
||||||
|
int&& ae3{A<true>()}; // expected-error {{no viable conversion}}
|
||||||
|
int ae4{A_true}; // expected-error {{no viable conversion}}
|
||||||
|
const int& ae5{A_true}; // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
|
int ap0((A<true>())); // expected-error {{no viable conversion}}
|
||||||
|
const int& ap1((A<true>())); // expected-error {{no viable conversion}}
|
||||||
|
int&& ap3((A<true>())); // expected-error {{no viable conversion}}
|
||||||
|
int ap4(A_true); // expected-error {{no viable conversion}}
|
||||||
|
const int& ap5(A_true); // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
|
B b0 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
const B & b1 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
B && b3 = A<true>(); // expected-error {{no viable conversion}}
|
||||||
|
B b4 = A_true; // expected-error {{no viable conversion}}
|
||||||
|
const B & b5 = A_true; // expected-error {{no viable conversion}}
|
||||||
|
|
||||||
|
B be0(A<true>());
|
||||||
|
const B& be1(A<true>());
|
||||||
|
B&& be3(A<true>());
|
||||||
|
B be4(A_true);
|
||||||
|
const B& be5(A_true);
|
||||||
|
|
||||||
|
B c0 = A<false>();
|
||||||
|
const B & c1 = A<false>();
|
||||||
|
B && c3 = A<false>();
|
||||||
|
B c4 = A_false;
|
||||||
|
const B & c5 = A_false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace parameter_pack {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct A {
|
||||||
|
// expected-note@-1+ {{candidate constructor}}
|
||||||
|
// expected-note@-2+ {{candidate function}}
|
||||||
|
template<typename ... Ts>
|
||||||
|
explicit((is_same<T, Ts>::value && ...))
|
||||||
|
// expected-note@-1 {{explicit(bool) specifier resolved to true}}
|
||||||
|
A(Ts...);
|
||||||
|
// expected-note@-1 {{candidate constructor}}
|
||||||
|
// expected-note@-2 {{explicit constructor}}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
template<typename ... Ts>
|
||||||
|
A<T>::A(Ts ...) {}
|
||||||
|
|
||||||
|
void f() {
|
||||||
|
|
||||||
|
A<int> a0 = 0; // expected-error {{no viable conversion}}
|
||||||
|
A<int> a1( 0, 1);
|
||||||
|
A<int> a2{ 0, 1};
|
||||||
|
A<int> a3 = { 0, 1}; // expected-error {{chosen constructor is explicit}}
|
||||||
|
|
||||||
|
a1 = 0; // expected-error {{no viable overloaded '='}}
|
||||||
|
a2 = { 0, 1}; // expected-error {{no viable overloaded '='}}
|
||||||
|
|
||||||
|
A<double> b0 = 0;
|
||||||
|
A<double> b1( 0, 1);
|
||||||
|
A<double> b2{ 0, 1};
|
||||||
|
A<double> b3 = { 0, 1};
|
||||||
|
|
||||||
|
b1 = 0;
|
||||||
|
b2 = { 0, 1};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace deduction_guide {
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
struct B {};
|
||||||
|
|
||||||
|
B<true> b_true;
|
||||||
|
B<false> b_false;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct nondeduced
|
||||||
|
{
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2, bool b>
|
||||||
|
struct A {
|
||||||
|
// expected-note@-1+ {{candidate function}}
|
||||||
|
explicit(false)
|
||||||
|
A(typename nondeduced<T1>::type, typename nondeduced<T2>::type, typename nondeduced<B<b>>::type) {}
|
||||||
|
// expected-note@-1+ {{candidate template ignored}}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2, bool b>
|
||||||
|
explicit(enable_ifv<is_same<T1, T2>::value, b>::value)
|
||||||
|
A(T1, T2, B<b>) -> A<T1, T2, b>;
|
||||||
|
// expected-note@-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<bool b>
|
||||||
|
struct A {
|
||||||
|
//expected-note@-1+ {{candidate function}}
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
explicit(b)
|
||||||
|
A(T1, T2) {}
|
||||||
|
//expected-note@-1 {{explicit constructor declared here}}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
explicit(!is_same<T1, int>::value)
|
||||||
|
A(T1, T2) -> A<!is_same<int, T2>::value>;
|
||||||
|
// expected-note@-1+ {{explicit deduction guide declared here}}
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
A<b> v();
|
||||||
|
|
||||||
|
void f() {
|
||||||
|
|
||||||
|
A a0( 0, 1);
|
||||||
|
A a1{ 0, 1};
|
||||||
|
A a2 = { 0, 1};
|
||||||
|
auto a4 = A( 0, 1);
|
||||||
|
auto a5 = A{ 0, 1};
|
||||||
|
auto a6(v<false>());
|
||||||
|
a6 = { 0, 1};
|
||||||
|
|
||||||
|
A b0( 0.0, 1);
|
||||||
|
A b1{ 0.0, 1};
|
||||||
|
A b2 = { 0.0, 1}; // expected-error {{explicit deduction guide for copy-list-initialization}}
|
||||||
|
auto b4 = A( 0.0, 1);
|
||||||
|
auto b5 = A{ 0.0, 1};
|
||||||
|
|
||||||
|
A c0( 0, 1.0);
|
||||||
|
A c1{ 0, 1.0};
|
||||||
|
A c2 = { 0, 1.0}; // expected-error {{chosen constructor is explicit}}
|
||||||
|
auto c4 = A( 0, 1.0);
|
||||||
|
auto c5 = A{ 0, 1.0};
|
||||||
|
auto c6(v<true>());
|
||||||
|
c0 = { 0, 1.0}; // expected-error {{no viable overloaded '='}}
|
||||||
|
|
||||||
|
A d0( 0.0, 1.0);
|
||||||
|
A d1{ 0.0, 1.0};
|
||||||
|
A d2 = { 0.0, 1.0}; // expected-error {{explicit deduction guide for copy-list-initialization}}
|
||||||
|
auto d4 = A( 0.0, 1.0);
|
||||||
|
auto d5 = A{ 0.0, 1.0};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace conversion3 {
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
struct A {
|
||||||
|
explicit(!b) operator int();
|
||||||
|
explicit(b) operator bool();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
A<b>::operator bool() { return false; }
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
void f(int);
|
||||||
|
void f(bool);
|
||||||
|
};
|
||||||
|
|
||||||
|
void f(A<true> a, B b) {
|
||||||
|
b.f(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
void f1(A<false> a, B b) {
|
||||||
|
b.f(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taken from 12.3.2p2
|
||||||
|
class X { X(); };
|
||||||
|
class Y { }; // expected-note+ {{candidate constructor (the implicit}}
|
||||||
|
|
||||||
|
template<bool b>
|
||||||
|
struct Z {
|
||||||
|
explicit(b) operator X() const;
|
||||||
|
explicit(b) operator Y() const;
|
||||||
|
explicit(b) operator int() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
void testExplicit()
|
||||||
|
{
|
||||||
|
Z<true> z;
|
||||||
|
// 13.3.1.4p1 & 8.5p16:
|
||||||
|
Y y2 = z; // expected-error {{no viable conversion}}
|
||||||
|
Y y2b(z);
|
||||||
|
Y y3 = (Y)z;
|
||||||
|
Y y4 = Y(z);
|
||||||
|
Y y5 = static_cast<Y>(z);
|
||||||
|
// 13.3.1.5p1 & 8.5p16:
|
||||||
|
int i1 = (int)z;
|
||||||
|
int i2 = int(z);
|
||||||
|
int i3 = static_cast<int>(z);
|
||||||
|
int i4(z);
|
||||||
|
// 13.3.1.6p1 & 8.5.3p5:
|
||||||
|
const Y& y6 = z; // expected-error {{no viable conversion}}
|
||||||
|
const int& y7 = z; // expected-error {{no viable conversion}}
|
||||||
|
const Y& y8(z);
|
||||||
|
const int& y9(z);
|
||||||
|
|
||||||
|
// Y is an aggregate, so aggregate-initialization is performed and the
|
||||||
|
// conversion function is not considered.
|
||||||
|
const Y y10{z}; // expected-error {{excess elements}}
|
||||||
|
const Y& y11{z}; // expected-error {{excess elements}} expected-note {{in initialization of temporary}}
|
||||||
|
const int& y12{z};
|
||||||
|
|
||||||
|
// X is not an aggregate, so constructors are considered,
|
||||||
|
// per 13.3.3.1/4 & DR1467.
|
||||||
|
const X x1{z};
|
||||||
|
const X& x2{z};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tmp {};
|
||||||
|
|
||||||
|
template<typename T1>
|
||||||
|
struct C {
|
||||||
|
template<typename T>
|
||||||
|
explicit(!is_same<T1, T>::value)
|
||||||
|
// expected-note@-1+ {{explicit(bool) specifier resolved to true}}
|
||||||
|
operator T();
|
||||||
|
// expected-note@-1+ {{candidate conversion operator ignored}}
|
||||||
|
};
|
||||||
|
|
||||||
|
using Bool = C<bool>;
|
||||||
|
using Integral = C<int>;
|
||||||
|
using Unrelated = C<tmp>;
|
||||||
|
|
||||||
|
void testBool() {
|
||||||
|
Bool b;
|
||||||
|
Integral n;
|
||||||
|
Unrelated u;
|
||||||
|
|
||||||
|
(void) (1 + b); // expected-error {{invalid operands to binary expression}}
|
||||||
|
(void) (1 + n);
|
||||||
|
(void) (1 + u); // expected-error {{invalid operands to binary expression}}
|
||||||
|
|
||||||
|
// 5.3.1p9:
|
||||||
|
(void) (!b);
|
||||||
|
(void) (!n);
|
||||||
|
(void) (!u);
|
||||||
|
|
||||||
|
// 5.14p1:
|
||||||
|
(void) (b && true);
|
||||||
|
(void) (n && true);
|
||||||
|
(void) (u && true);
|
||||||
|
|
||||||
|
// 5.15p1:
|
||||||
|
(void) (b || true);
|
||||||
|
(void) (n || true);
|
||||||
|
(void) (u || true);
|
||||||
|
|
||||||
|
// 5.16p1:
|
||||||
|
(void) (b ? 0 : 1);
|
||||||
|
(void) (n ? 0: 1);
|
||||||
|
(void) (u ? 0: 1);
|
||||||
|
|
||||||
|
// // 5.19p5:
|
||||||
|
// // TODO: After constexpr has been implemented
|
||||||
|
|
||||||
|
// 6.4p4:
|
||||||
|
if (b) {}
|
||||||
|
if (n) {}
|
||||||
|
if (u) {}
|
||||||
|
|
||||||
|
// 6.4.2p2:
|
||||||
|
switch (b) {} // expected-error {{statement requires expression of integer type}}
|
||||||
|
switch (n) {} // expected-error {{statement requires expression of integer type}}
|
||||||
|
switch (u) {} // expected-error {{statement requires expression of integer type}}
|
||||||
|
|
||||||
|
// 6.5.1:
|
||||||
|
while (b) {}
|
||||||
|
while (n) {}
|
||||||
|
while (u) {}
|
||||||
|
|
||||||
|
// 6.5.2p1:
|
||||||
|
do {} while (b);
|
||||||
|
do {} while (n);
|
||||||
|
do {} while (u);
|
||||||
|
|
||||||
|
// 6.5.3:
|
||||||
|
for (;b;) {}
|
||||||
|
for (;n;) {}
|
||||||
|
for (;u;) {}
|
||||||
|
|
||||||
|
// 13.3.1.5p1:
|
||||||
|
bool db1(b);
|
||||||
|
bool db2(n);
|
||||||
|
bool db3(u);
|
||||||
|
int di1(b);
|
||||||
|
int di2(n);
|
||||||
|
int di3(n);
|
||||||
|
const bool &direct_cr1(b);
|
||||||
|
const bool &direct_cr2(n);
|
||||||
|
const bool &direct_cr3(n);
|
||||||
|
const int &direct_cr4(b);
|
||||||
|
const int &direct_cr5(n);
|
||||||
|
const int &direct_cr6(n);
|
||||||
|
bool directList1{b};
|
||||||
|
bool directList2{n};
|
||||||
|
bool directList3{n};
|
||||||
|
int directList4{b};
|
||||||
|
int directList5{n};
|
||||||
|
int directList6{n};
|
||||||
|
const bool &directList_cr1{b};
|
||||||
|
const bool &directList_cr2{n};
|
||||||
|
const bool &directList_cr3{n};
|
||||||
|
const int &directList_cr4{b};
|
||||||
|
const int &directList_cr5{n};
|
||||||
|
const int &directList_cr6{n};
|
||||||
|
bool copy1 = b;
|
||||||
|
bool copy2 = n;// expected-error {{no viable conversion}}
|
||||||
|
bool copyu2 = u;// expected-error {{no viable conversion}}
|
||||||
|
int copy3 = b;// expected-error {{no viable conversion}}
|
||||||
|
int copy4 = n;
|
||||||
|
int copyu4 = u;// expected-error {{no viable conversion}}
|
||||||
|
const bool ©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<typename T1 = int, typename T2 = int>
|
||||||
|
struct A {
|
||||||
|
// expected-note@-1+ {{candidate template ignored}}
|
||||||
|
explicit(!is_same<T1, T2>::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<typename T1, typename T2>
|
||||||
|
explicit A(T1, T2) -> A<T1, T2>;
|
||||||
|
// 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}}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s
|
||||||
|
|
||||||
namespace Constructor {
|
namespace Constructor {
|
||||||
struct A {
|
struct A {
|
||||||
A(int);
|
A(int);
|
||||||
|
@ -183,7 +185,8 @@ namespace Conversion {
|
||||||
const int ©List7 = {b};
|
const int ©List7 = {b};
|
||||||
const int ©List8 = {n}; // expected-error {{no viable conversion}}
|
const int ©List8 = {n}; // expected-error {{no viable conversion}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if __cplusplus < 201707L
|
||||||
void testNew()
|
void testNew()
|
||||||
{
|
{
|
||||||
// 5.3.4p6:
|
// 5.3.4p6:
|
||||||
|
@ -200,7 +203,8 @@ namespace Conversion {
|
||||||
new int[i];
|
new int[i];
|
||||||
new int[ni]; // expected-error {{array size expression of type 'NotInt' requires explicit conversion to type 'int'}}
|
new int[ni]; // expected-error {{array size expression of type 'NotInt' requires explicit conversion to type 'int'}}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void testDelete()
|
void testDelete()
|
||||||
{
|
{
|
||||||
// 5.3.5pp2:
|
// 5.3.5pp2:
|
||||||
|
|
|
@ -34,6 +34,9 @@ ArgVector getBasicRunOptionsForLanguage(Language Lang) {
|
||||||
case Lang_CXX14:
|
case Lang_CXX14:
|
||||||
BasicArgs = {"-std=c++14", "-frtti"};
|
BasicArgs = {"-std=c++14", "-frtti"};
|
||||||
break;
|
break;
|
||||||
|
case Lang_CXX2a:
|
||||||
|
BasicArgs = {"-std=c++2a", "-frtti"};
|
||||||
|
break;
|
||||||
case Lang_OpenCL:
|
case Lang_OpenCL:
|
||||||
case Lang_OBJCXX:
|
case Lang_OBJCXX:
|
||||||
llvm_unreachable("Not implemented yet!");
|
llvm_unreachable("Not implemented yet!");
|
||||||
|
|
|
@ -28,6 +28,7 @@ enum Language {
|
||||||
Lang_CXX,
|
Lang_CXX,
|
||||||
Lang_CXX11,
|
Lang_CXX11,
|
||||||
Lang_CXX14,
|
Lang_CXX14,
|
||||||
|
Lang_CXX2a,
|
||||||
Lang_OpenCL,
|
Lang_OpenCL,
|
||||||
Lang_OBJCXX
|
Lang_OBJCXX
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,6 +108,10 @@ testing::AssertionResult MatchVerifier<NodeType>::match(
|
||||||
Args.push_back("-std=c++14");
|
Args.push_back("-std=c++14");
|
||||||
FileName = "input.cc";
|
FileName = "input.cc";
|
||||||
break;
|
break;
|
||||||
|
case Lang_CXX2a:
|
||||||
|
Args.push_back("-std=c++2a");
|
||||||
|
FileName = "input.cc";
|
||||||
|
break;
|
||||||
case Lang_OpenCL:
|
case Lang_OpenCL:
|
||||||
FileName = "input.cl";
|
FileName = "input.cl";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -806,6 +806,26 @@ TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
|
||||||
EXPECT_FALSE(testStructuralMatch(t));
|
EXPECT_FALSE(testStructuralMatch(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StructuralEquivalenceTest, ExplicitBoolDifferent) {
|
||||||
|
auto Decls = makeNamedDecls("struct foo {explicit(false) foo(int);};",
|
||||||
|
"struct foo {explicit(true) foo(int);};", Lang_CXX2a);
|
||||||
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<0>(Decls), cxxConstructorDecl(hasName("foo")));
|
||||||
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<1>(Decls), cxxConstructorDecl(hasName("foo")));
|
||||||
|
EXPECT_FALSE(testStructuralMatch(First, Second));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) {
|
||||||
|
auto Decls = makeNamedDecls("struct foo {explicit(true) foo(int);};",
|
||||||
|
"struct foo {explicit(true) foo(int);};", Lang_CXX2a);
|
||||||
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<0>(Decls), cxxConstructorDecl(hasName("foo")));
|
||||||
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<1>(Decls), cxxConstructorDecl(hasName("foo")));
|
||||||
|
EXPECT_TRUE(testStructuralMatch(First, Second));
|
||||||
|
}
|
||||||
|
|
||||||
struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
|
struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};
|
||||||
|
|
||||||
TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
|
TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
|
||||||
|
@ -853,5 +873,25 @@ TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
|
||||||
EXPECT_FALSE(testStructuralMatch(t));
|
EXPECT_FALSE(testStructuralMatch(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
|
||||||
|
auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
|
||||||
|
"template <bool b> struct foo {explicit(b) foo(int);};", Lang_CXX2a);
|
||||||
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
||||||
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
||||||
|
EXPECT_TRUE(testStructuralMatch(First, Second));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
|
||||||
|
auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
|
||||||
|
"template <bool b> struct foo {explicit(!b) foo(int);};", Lang_CXX2a);
|
||||||
|
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
||||||
|
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
|
||||||
|
get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
|
||||||
|
EXPECT_FALSE(testStructuralMatch(First, Second));
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace ast_matchers
|
} // end namespace ast_matchers
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
|
@ -1002,7 +1002,7 @@ as the draft C++2a standard evolves.
|
||||||
<tr>
|
<tr>
|
||||||
<td><tt>explicit(bool)</tt></td>
|
<td><tt>explicit(bool)</tt></td>
|
||||||
<td><a href="http://wg21.link/p0892r2">P0892R2</a></td>
|
<td><a href="http://wg21.link/p0892r2">P0892R2</a></td>
|
||||||
<td class="none" align="center">No</td>
|
<td class="full" align="center">SVN</td>
|
||||||
</tr>
|
</tr>
|
||||||
<!-- San Diego papers -->
|
<!-- San Diego papers -->
|
||||||
<tr>
|
<tr>
|
||||||
|
|
Loading…
Reference in New Issue