8 changes: 8 additions & 0 deletions clang/include/clang/Basic/Specifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
#include "llvm/Support/ErrorHandling.h"

namespace clang {

/// Define the meaning of possible values of the kind in ExplicitSpecifier.
enum class ExplicitSpecKind : unsigned {
ResolvedFalse,
ResolvedTrue,
Unresolved,
};

/// Specifies the width of a type, e.g., short, long, or long long.
enum TypeSpecifierWidth {
TSW_unspecified,
Expand Down
62 changes: 33 additions & 29 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#ifndef LLVM_CLANG_SEMA_DECLSPEC_H
#define LLVM_CLANG_SEMA_DECLSPEC_H

#include "clang/AST/DeclCXX.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/Lambda.h"
Expand Down Expand Up @@ -356,7 +357,6 @@ class DeclSpec {
unsigned FS_inline_specified : 1;
unsigned FS_forceinline_specified: 1;
unsigned FS_virtual_specified : 1;
unsigned FS_explicit_specified : 1;
unsigned FS_noreturn_specified : 1;

// friend-specifier
Expand All @@ -371,6 +371,9 @@ class DeclSpec {
Expr *ExprRep;
};

/// ExplicitSpecifier - Store information about explicit spicifer.
ExplicitSpecifier FS_explicit_specifier;

// attributes.
ParsedAttributes Attrs;

Expand All @@ -393,6 +396,7 @@ class DeclSpec {
SourceLocation TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc,
TQ_unalignedLoc;
SourceLocation FS_inlineLoc, FS_virtualLoc, FS_explicitLoc, FS_noreturnLoc;
SourceLocation FS_explicitCloseParenLoc;
SourceLocation FS_forceinlineLoc;
SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
SourceLocation TQ_pipeLoc;
Expand Down Expand Up @@ -420,31 +424,18 @@ class DeclSpec {
}

DeclSpec(AttributeFactory &attrFactory)
: StorageClassSpec(SCS_unspecified),
ThreadStorageClassSpec(TSCS_unspecified),
SCS_extern_in_linkage_spec(false),
TypeSpecWidth(TSW_unspecified),
TypeSpecComplex(TSC_unspecified),
TypeSpecSign(TSS_unspecified),
TypeSpecType(TST_unspecified),
TypeAltiVecVector(false),
TypeAltiVecPixel(false),
TypeAltiVecBool(false),
TypeSpecOwned(false),
TypeSpecPipe(false),
TypeSpecSat(false),
TypeQualifiers(TQ_unspecified),
FS_inline_specified(false),
FS_forceinline_specified(false),
FS_virtual_specified(false),
FS_explicit_specified(false),
FS_noreturn_specified(false),
Friend_specified(false),
Constexpr_specified(false),
Attrs(attrFactory),
writtenBS(),
ObjCQualifiers(nullptr) {
}
: StorageClassSpec(SCS_unspecified),
ThreadStorageClassSpec(TSCS_unspecified),
SCS_extern_in_linkage_spec(false), TypeSpecWidth(TSW_unspecified),
TypeSpecComplex(TSC_unspecified), TypeSpecSign(TSS_unspecified),
TypeSpecType(TST_unspecified), TypeAltiVecVector(false),
TypeAltiVecPixel(false), TypeAltiVecBool(false), TypeSpecOwned(false),
TypeSpecPipe(false), TypeSpecSat(false), TypeQualifiers(TQ_unspecified),
FS_inline_specified(false), FS_forceinline_specified(false),
FS_virtual_specified(false), FS_noreturn_specified(false),
Friend_specified(false), Constexpr_specified(false),
FS_explicit_specifier(), Attrs(attrFactory), writtenBS(),
ObjCQualifiers(nullptr) {}

// storage-class-specifier
SCS getStorageClassSpec() const { return (SCS)StorageClassSpec; }
Expand Down Expand Up @@ -570,11 +561,22 @@ class DeclSpec {
return FS_inline_specified ? FS_inlineLoc : FS_forceinlineLoc;
}

ExplicitSpecifier getExplicitSpecifier() const {
return FS_explicit_specifier;
}

bool isVirtualSpecified() const { return FS_virtual_specified; }
SourceLocation getVirtualSpecLoc() const { return FS_virtualLoc; }

bool isExplicitSpecified() const { return FS_explicit_specified; }
bool hasExplicitSpecifier() const {
return FS_explicit_specifier.isSpecified();
}
SourceLocation getExplicitSpecLoc() const { return FS_explicitLoc; }
SourceRange getExplicitSpecRange() const {
return FS_explicit_specifier.getExpr()
? SourceRange(FS_explicitLoc, FS_explicitCloseParenLoc)
: SourceRange(FS_explicitLoc);
}

bool isNoreturnSpecified() const { return FS_noreturn_specified; }
SourceLocation getNoreturnSpecLoc() const { return FS_noreturnLoc; }
Expand All @@ -586,8 +588,9 @@ class DeclSpec {
FS_forceinlineLoc = SourceLocation();
FS_virtual_specified = false;
FS_virtualLoc = SourceLocation();
FS_explicit_specified = false;
FS_explicit_specifier = ExplicitSpecifier();
FS_explicitLoc = SourceLocation();
FS_explicitCloseParenLoc = SourceLocation();
FS_noreturn_specified = false;
FS_noreturnLoc = SourceLocation();
}
Expand Down Expand Up @@ -706,7 +709,8 @@ class DeclSpec {
bool setFunctionSpecVirtual(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
bool setFunctionSpecExplicit(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);
unsigned &DiagID, ExplicitSpecifier ExplicitSpec,
SourceLocation CloseParenLoc);
bool setFunctionSpecNoreturn(SourceLocation Loc, const char *&PrevSpec,
unsigned &DiagID);

Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Overload.h
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,11 @@ class Sema;
/// attribute disabled it.
ovl_fail_enable_if,

/// This candidate constructor or conversion fonction
/// is used implicitly but the explicit(bool) specifier
/// was resolved to true
ovl_fail_explicit_resolved,

/// This candidate was not viable because its address could not be taken.
ovl_fail_addr_not_available,

Expand Down
40 changes: 23 additions & 17 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2743,7 +2743,8 @@ class Sema {
CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
CCEK_TemplateArg, ///< Value of a non-type template parameter.
CCEK_NewExpr, ///< Constant expression in a noptr-new-declarator.
CCEK_ConstexprIf ///< Condition in a constexpr if statement.
CCEK_ConstexprIf, ///< Condition in a constexpr if statement.
CCEK_ExplicitBool ///< Condition in an explicit(bool) specifier.
};
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
llvm::APSInt &Value, CCEKind CCE);
Expand Down Expand Up @@ -2865,7 +2866,8 @@ class Sema {
OverloadCandidateSet &CandidateSet,
bool SuppressUserConversions = false,
bool PartialOverloading = false,
bool AllowExplicit = false,
bool AllowExplicit = true,
bool AllowExplicitConversion = false,
ADLCallKind IsADLCandidate = ADLCallKind::NotADL,
ConversionSequenceList EarlyConversions = None);
void AddFunctionCandidates(const UnresolvedSetImpl &Functions,
Expand Down Expand Up @@ -2904,7 +2906,7 @@ class Sema {
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args,
OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false,
bool PartialOverloading = false,
bool PartialOverloading = false, bool AllowExplicit = true,
ADLCallKind IsADLCandidate = ADLCallKind::NotADL);
bool CheckNonDependentConversions(FunctionTemplateDecl *FunctionTemplate,
ArrayRef<QualType> ParamTypes,
Expand All @@ -2916,20 +2918,16 @@ class Sema {
QualType ObjectType = QualType(),
Expr::Classification
ObjectClassification = {});
void AddConversionCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet,
bool AllowObjCConversionOnExplicit,
bool AllowResultConversion = true);
void AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet,
bool AllowObjCConversionOnExplicit,
bool AllowResultConversion = true);
void AddConversionCandidate(
CXXConversionDecl *Conversion, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
bool AllowExplicit, bool AllowResultConversion = true);
void AddTemplateConversionCandidate(
FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext, Expr *From, QualType ToType,
OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit,
bool AllowExplicit, bool AllowResultConversion = true);
void AddSurrogateCandidate(CXXConversionDecl *Conversion,
DeclAccessPair FoundDecl,
CXXRecordDecl *ActingContext,
Expand Down Expand Up @@ -10158,6 +10156,14 @@ class Sema {
ExprResult CheckBooleanCondition(SourceLocation Loc, Expr *E,
bool IsConstexpr = false);

/// ActOnExplicitBoolSpecifier - Build an ExplicitSpecifier from an expression
/// found in an explicit(bool) specifier.
ExplicitSpecifier ActOnExplicitBoolSpecifier(Expr *E);

/// tryResolveExplicitSpecifier - Attempt to resolve the explict specifier.
/// Returns true if the explicit specifier is now resolved.
bool tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec);

/// DiagnoseAssignmentAsCondition - Given that an expression is
/// being used as a boolean condition, warn if it's an assignment.
void DiagnoseAssignmentAsCondition(Expr *E);
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1441,9 +1441,6 @@ namespace serialization {
/// A CXXConstructorDecl record.
DECL_CXX_CONSTRUCTOR,

/// A CXXConstructorDecl record for an inherited constructor.
DECL_CXX_INHERITED_CONSTRUCTOR,

/// A CXXDestructorDecl record.
DECL_CXX_DESTRUCTOR,

Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Serialization/ASTReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -2430,6 +2430,14 @@ class ASTRecordReader {
ID);
}

ExplicitSpecifier readExplicitSpec() {
uint64_t Kind = readInt();
bool HasExpr = Kind & 0x1;
Kind = Kind >> 1;
return ExplicitSpecifier(HasExpr ? readExpr() : nullptr,
static_cast<ExplicitSpecKind>(Kind));
}

void readExceptionSpec(SmallVectorImpl<QualType> &ExceptionStorage,
FunctionProtoType::ExceptionSpecInfo &ESI) {
return Reader->readExceptionSpec(*F, ExceptionStorage, ESI, Record, Idx);
Expand Down
28 changes: 23 additions & 5 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3076,11 +3076,20 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
// Create the imported function.
FunctionDecl *ToFunction = nullptr;
if (auto *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) {
Expr *ExplicitExpr = nullptr;
if (FromConstructor->getExplicitSpecifier().getExpr()) {
auto Imp = importSeq(FromConstructor->getExplicitSpecifier().getExpr());
if (!Imp)
return Imp.takeError();
std::tie(ExplicitExpr) = *Imp;
}
if (GetImportedOrCreateDecl<CXXConstructorDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo,
FromConstructor->isExplicit(),
D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo,
ExplicitSpecifier(
ExplicitExpr,
FromConstructor->getExplicitSpecifier().getKind()),
D->isInlineSpecified(), D->isImplicit(), D->isConstexpr()))
return ToFunction;
} else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) {

Expand All @@ -3106,10 +3115,19 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) {
ToDtor->setOperatorDelete(ToOperatorDelete, ToThisArg);
} else if (CXXConversionDecl *FromConversion =
dyn_cast<CXXConversionDecl>(D)) {
Expr *ExplicitExpr = nullptr;
if (FromConversion->getExplicitSpecifier().getExpr()) {
auto Imp = importSeq(FromConversion->getExplicitSpecifier().getExpr());
if (!Imp)
return Imp.takeError();
std::tie(ExplicitExpr) = *Imp;
}
if (GetImportedOrCreateDecl<CXXConversionDecl>(
ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC),
ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(),
FromConversion->isExplicit(), D->isConstexpr(), SourceLocation()))
ExplicitSpecifier(ExplicitExpr,
FromConversion->getExplicitSpecifier().getKind()),
D->isConstexpr(), SourceLocation()))
return ToFunction;
} else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) {
if (GetImportedOrCreateDecl<CXXMethodDecl>(
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -982,13 +982,15 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,

if (auto *Constructor1 = dyn_cast<CXXConstructorDecl>(Method1)) {
auto *Constructor2 = cast<CXXConstructorDecl>(Method2);
if (Constructor1->isExplicit() != Constructor2->isExplicit())
if (!Constructor1->getExplicitSpecifier().isEquivalent(
Constructor2->getExplicitSpecifier()))
return false;
}

if (auto *Conversion1 = dyn_cast<CXXConversionDecl>(Method1)) {
auto *Conversion2 = cast<CXXConversionDecl>(Method2);
if (Conversion1->isExplicit() != Conversion2->isExplicit())
if (!Conversion1->getExplicitSpecifier().isEquivalent(
Conversion2->getExplicitSpecifier()))
return false;
if (!IsStructurallyEquivalent(Context, Conversion1->getConversionType(),
Conversion2->getConversionType()))
Expand Down
1 change: 0 additions & 1 deletion clang/lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2713,7 +2713,6 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC,
FunctionDeclBits.SClass = S;
FunctionDeclBits.IsInline = isInlineSpecified;
FunctionDeclBits.IsInlineSpecified = isInlineSpecified;
FunctionDeclBits.IsExplicitSpecified = false;
FunctionDeclBits.IsVirtualAsWritten = false;
FunctionDeclBits.IsPure = false;
FunctionDeclBits.HasInheritedPrototype = false;
Expand Down
109 changes: 70 additions & 39 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1879,19 +1879,47 @@ bool CXXRecordDecl::mayBeAbstract() const {

void CXXDeductionGuideDecl::anchor() {}

bool ExplicitSpecifier::isEquivalent(const ExplicitSpecifier Other) const {
if ((getKind() != Other.getKind() ||
getKind() == ExplicitSpecKind::Unresolved)) {
if (getKind() == ExplicitSpecKind::Unresolved &&
Other.getKind() == ExplicitSpecKind::Unresolved) {
ODRHash SelfHash, OtherHash;
SelfHash.AddStmt(getExpr());
OtherHash.AddStmt(Other.getExpr());
return SelfHash.CalculateHash() == OtherHash.CalculateHash();
} else
return false;
}
return true;
}

ExplicitSpecifier ExplicitSpecifier::getFromDecl(FunctionDecl *Function) {
switch (Function->getDeclKind()) {
case Decl::Kind::CXXConstructor:
return cast<CXXConstructorDecl>(Function)->getExplicitSpecifier();
case Decl::Kind::CXXConversion:
return cast<CXXConversionDecl>(Function)->getExplicitSpecifier();
case Decl::Kind::CXXDeductionGuide:
return cast<CXXDeductionGuideDecl>(Function)->getExplicitSpecifier();
default:
return {};
}
}

CXXDeductionGuideDecl *CXXDeductionGuideDecl::Create(
ASTContext &C, DeclContext *DC, SourceLocation StartLoc, bool IsExplicit,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
SourceLocation EndLocation) {
return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, IsExplicit,
NameInfo, T, TInfo, EndLocation);
ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
ExplicitSpecifier ES, const DeclarationNameInfo &NameInfo, QualType T,
TypeSourceInfo *TInfo, SourceLocation EndLocation) {
return new (C, DC) CXXDeductionGuideDecl(C, DC, StartLoc, ES, NameInfo, T,
TInfo, EndLocation);
}

CXXDeductionGuideDecl *CXXDeductionGuideDecl::CreateDeserialized(ASTContext &C,
unsigned ID) {
return new (C, ID) CXXDeductionGuideDecl(C, nullptr, SourceLocation(), false,
DeclarationNameInfo(), QualType(),
nullptr, SourceLocation());
return new (C, ID) CXXDeductionGuideDecl(
C, nullptr, SourceLocation(), ExplicitSpecifier(), DeclarationNameInfo(),
QualType(), nullptr, SourceLocation());
}

void CXXMethodDecl::anchor() {}
Expand Down Expand Up @@ -2329,47 +2357,54 @@ SourceRange CXXCtorInitializer::getSourceRange() const {
CXXConstructorDecl::CXXConstructorDecl(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool isExplicitSpecified, bool isInline, bool isImplicitlyDeclared,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
bool isConstexpr, InheritedConstructor Inherited)
: CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo,
SC_None, isInline, isConstexpr, SourceLocation()) {
setNumCtorInitializers(0);
setInheritingConstructor(static_cast<bool>(Inherited));
setImplicit(isImplicitlyDeclared);
CXXConstructorDeclBits.HasTrailingExplicitSpecifier = ES.getExpr() ? 1 : 0;
if (Inherited)
*getTrailingObjects<InheritedConstructor>() = Inherited;
setExplicitSpecified(isExplicitSpecified);
setExplicitSpecifier(ES);
}

void CXXConstructorDecl::anchor() {}

CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C,
unsigned ID,
bool Inherited) {
unsigned Extra = additionalSizeToAlloc<InheritedConstructor>(Inherited);
uint64_t AllocKind) {
bool hasTraillingExplicit = static_cast<bool>(AllocKind & TAKHasTailExplicit);
bool isInheritingConstructor =
static_cast<bool>(AllocKind & TAKInheritsConstructor);
unsigned Extra =
additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
isInheritingConstructor, hasTraillingExplicit);
auto *Result = new (C, ID, Extra) CXXConstructorDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
false, false, false, false, InheritedConstructor());
Result->setInheritingConstructor(Inherited);
ExplicitSpecifier(), false, false, false, InheritedConstructor());
Result->setInheritingConstructor(isInheritingConstructor);
Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier =
hasTraillingExplicit;
Result->setExplicitSpecifier(ExplicitSpecifier());
return Result;
}

CXXConstructorDecl *
CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isExplicit, bool isInline,
bool isImplicitlyDeclared, bool isConstexpr,
InheritedConstructor Inherited) {
CXXConstructorDecl *CXXConstructorDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared,
bool isConstexpr, InheritedConstructor Inherited) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConstructorName &&
"Name must refer to a constructor");
unsigned Extra =
additionalSizeToAlloc<InheritedConstructor>(Inherited ? 1 : 0);
return new (C, RD, Extra) CXXConstructorDecl(
C, RD, StartLoc, NameInfo, T, TInfo, isExplicit, isInline,
isImplicitlyDeclared, isConstexpr, Inherited);
additionalSizeToAlloc<InheritedConstructor, ExplicitSpecifier>(
Inherited ? 1 : 0, ES.getExpr() ? 1 : 0);
return new (C, RD, Extra)
CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline,
isImplicitlyDeclared, isConstexpr, Inherited);
}

CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const {
Expand Down Expand Up @@ -2520,25 +2555,21 @@ void CXXConversionDecl::anchor() {}

CXXConversionDecl *
CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
return new (C, ID) CXXConversionDecl(C, nullptr, SourceLocation(),
DeclarationNameInfo(), QualType(),
nullptr, false, false, false,
SourceLocation());
return new (C, ID) CXXConversionDecl(
C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr,
false, ExplicitSpecifier(), false, SourceLocation());
}

CXXConversionDecl *
CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD,
SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo,
QualType T, TypeSourceInfo *TInfo,
bool isInline, bool isExplicit,
bool isConstexpr, SourceLocation EndLocation) {
CXXConversionDecl *CXXConversionDecl::Create(
ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc,
const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo,
bool isInline, ExplicitSpecifier ES, bool isConstexpr,
SourceLocation EndLocation) {
assert(NameInfo.getName().getNameKind()
== DeclarationName::CXXConversionFunctionName &&
"Name must refer to a conversion function");
return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo,
isInline, isExplicit, isConstexpr,
EndLocation);
isInline, ES, isConstexpr, EndLocation);
}

bool CXXConversionDecl::isLambdaToBlockPointerConversion() const {
Expand Down
22 changes: 18 additions & 4 deletions clang/lib/AST/DeclPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,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) {
if (!D->getDescribedFunctionTemplate() &&
!D->isFunctionTemplateSpecialization())
Expand Down Expand Up @@ -596,10 +611,9 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) {
if (D->isVirtualAsWritten()) Out << "virtual ";
if (D->isModulePrivate()) Out << "__module_private__ ";
if (D->isConstexpr() && !D->isExplicitlyDefaulted()) Out << "constexpr ";
if ((CDecl && CDecl->isExplicitSpecified()) ||
(ConversionDecl && ConversionDecl->isExplicitSpecified()) ||
(GuideDecl && GuideDecl->isExplicitSpecified()))
Out << "explicit ";
ExplicitSpecifier ExplicitSpec = ExplicitSpecifier::getFromDecl(D);
if (ExplicitSpec.isSpecified())
printExplicitSpecifier(ExplicitSpec, Out, Policy, Indentation);
}

PrintingPolicy SubPolicy(Policy);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Frontend/InitPreprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts,
Builder.defineMacro("__cpp_template_template_args", "201611L");

// C++20 features.
if (LangOpts.CPlusPlus2a)
Builder.defineMacro("__cpp_conditional_explicit", "201806L");
if (LangOpts.Char8)
Builder.defineMacro("__cpp_char8_t", "201811L");
Builder.defineMacro("__cpp_impl_destroying_delete", "201806L");
Expand Down
62 changes: 49 additions & 13 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2480,12 +2480,12 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS, AccessSpecifier AS,
Diag(DS.getInlineSpecLoc(), diag::err_typename_invalid_functionspec);
if (DS.isVirtualSpecified())
Diag(DS.getVirtualSpecLoc(), diag::err_typename_invalid_functionspec);
if (DS.isExplicitSpecified())
if (DS.hasExplicitSpecifier())
Diag(DS.getExplicitSpecLoc(), diag::err_typename_invalid_functionspec);
DS.ClearFunctionSpecs();
}

// Issue diagnostic and remove constexpr specfier if present.
// Issue diagnostic and remove constexpr specifier if present.
if (DS.isConstexprSpecified() && DSC != DeclSpecContext::DSC_condition) {
Diag(DS.getConstexprSpecLoc(), diag::err_typename_invalid_constexpr);
DS.ClearConstexprSpec();
Expand Down Expand Up @@ -3004,9 +3004,13 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
while (1) {
bool isInvalid = false;
bool isStorageClass = false;
bool isAlreadyConsumed = false;
const char *PrevSpec = nullptr;
unsigned DiagID = 0;

// This value need to be set when isAlreadyConsumed is set to true.
SourceLocation RangeEnd;

// HACK: MSVC doesn't consider _Atomic to be a keyword and its STL
// implementation for VS2013 uses _Atomic as an identifier for one of the
// classes in <atomic>.
Expand Down Expand Up @@ -3558,9 +3562,34 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
isInvalid = DS.setFunctionSpecVirtual(Loc, PrevSpec, DiagID);
}
break;
case tok::kw_explicit:
isInvalid = DS.setFunctionSpecExplicit(Loc, PrevSpec, DiagID);
case tok::kw_explicit: {
SourceLocation ExplicitLoc = Loc;
SourceLocation CloseParenLoc;
ExplicitSpecifier ExplicitSpec(nullptr, ExplicitSpecKind::ResolvedTrue);
isAlreadyConsumed = true;
RangeEnd = ExplicitLoc;
ConsumeToken(); // kw_explicit
if (Tok.is(tok::l_paren)) {
if (getLangOpts().CPlusPlus2a) {
ExprResult ExplicitExpr(static_cast<Expr *>(nullptr));
BalancedDelimiterTracker Tracker(*this, tok::l_paren);
Tracker.consumeOpen();
ExplicitExpr = ParseConstantExpression();
RangeEnd = Tok.getLocation();
if (ExplicitExpr.isUsable()) {
CloseParenLoc = Tok.getLocation();
Tracker.consumeClose();
ExplicitSpec =
Actions.ActOnExplicitBoolSpecifier(ExplicitExpr.get());
} else
Tracker.skipToEnd();
} else
Diag(Tok.getLocation(), diag::warn_cxx2a_compat_explicit_bool);
}
isInvalid = DS.setFunctionSpecExplicit(ExplicitLoc, PrevSpec, DiagID,
ExplicitSpec, CloseParenLoc);
break;
}
case tok::kw__Noreturn:
if (!getLangOpts().C11)
Diag(Loc, diag::ext_c11_noreturn);
Expand Down Expand Up @@ -3904,25 +3933,32 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
// If a type specifier follows, it will be diagnosed elsewhere.
continue;
}

assert(!isAlreadyConsumed || RangeEnd != SourceLocation() &&
"both or neither of isAlreadyConsumed and "
"RangeEnd needs to be set");
DS.SetRangeEnd(isAlreadyConsumed ? RangeEnd : Tok.getLocation());

// If the specifier wasn't legal, issue a diagnostic.
if (isInvalid) {
assert(PrevSpec && "Method did not return previous specifier!");
assert(DiagID);

if (DiagID == diag::ext_duplicate_declspec ||
DiagID == diag::ext_warn_duplicate_declspec)
Diag(Tok, DiagID)
<< PrevSpec << FixItHint::CreateRemoval(Tok.getLocation());
DiagID == diag::ext_warn_duplicate_declspec ||
DiagID == diag::err_duplicate_declspec)
Diag(Loc, DiagID) << PrevSpec
<< FixItHint::CreateRemoval(
SourceRange(Loc, DS.getEndLoc()));
else if (DiagID == diag::err_opencl_unknown_type_specifier) {
Diag(Tok, DiagID) << getLangOpts().OpenCLCPlusPlus
<< getLangOpts().getOpenCLVersionTuple().getAsString()
<< PrevSpec << isStorageClass;
Diag(Loc, DiagID) << getLangOpts().OpenCLCPlusPlus
<< getLangOpts().getOpenCLVersionTuple().getAsString()
<< PrevSpec << isStorageClass;
} else
Diag(Tok, DiagID) << PrevSpec;
Diag(Loc, DiagID) << PrevSpec;
}

DS.SetRangeEnd(Tok.getLocation());
if (DiagID != diag::err_bool_redeclaration)
if (DiagID != diag::err_bool_redeclaration && !isAlreadyConsumed)
// After an error the next token can be an annotation token.
ConsumeAnyToken();

Expand Down
28 changes: 19 additions & 9 deletions clang/lib/Sema/DeclSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ unsigned DeclSpec::getParsedSpecifiers() const {
if (hasTypeSpecifier())
Res |= PQ_TypeSpecifier;

if (FS_inline_specified || FS_virtual_specified || FS_explicit_specified ||
if (FS_inline_specified || FS_virtual_specified || hasExplicitSpecifier() ||
FS_noreturn_specified || FS_forceinline_specified)
Res |= PQ_FunctionSpecifier;
return Res;
Expand Down Expand Up @@ -959,17 +959,24 @@ bool DeclSpec::setFunctionSpecVirtual(SourceLocation Loc,
}

bool DeclSpec::setFunctionSpecExplicit(SourceLocation Loc,
const char *&PrevSpec,
unsigned &DiagID) {
const char *&PrevSpec, unsigned &DiagID,
ExplicitSpecifier ExplicitSpec,
SourceLocation CloseParenLoc) {
assert((ExplicitSpec.getKind() == ExplicitSpecKind::ResolvedTrue ||
ExplicitSpec.getExpr()) &&
"invalid ExplicitSpecifier");
// 'explicit explicit' is ok, but warn as this is likely not what the user
// intended.
if (FS_explicit_specified) {
DiagID = diag::warn_duplicate_declspec;
if (hasExplicitSpecifier()) {
DiagID = (ExplicitSpec.getExpr() || FS_explicit_specifier.getExpr())
? diag::err_duplicate_declspec
: diag::ext_warn_duplicate_declspec;
PrevSpec = "explicit";
return true;
}
FS_explicit_specified = true;
FS_explicit_specifier = ExplicitSpec;
FS_explicitLoc = Loc;
FS_explicitCloseParenLoc = CloseParenLoc;
return false;
}

Expand Down Expand Up @@ -1311,23 +1318,26 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
// The explicit specifier shall be used only in the declaration of
// a constructor or conversion function within its class
// definition;
if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) {
if (isFriendSpecified() && (isVirtualSpecified() || hasExplicitSpecifier())) {
StringRef Keyword;
FixItHint Hint;
SourceLocation SCLoc;

if (isVirtualSpecified()) {
Keyword = "virtual";
SCLoc = getVirtualSpecLoc();
Hint = FixItHint::CreateRemoval(SCLoc);
} else {
Keyword = "explicit";
SCLoc = getExplicitSpecLoc();
Hint = FixItHint::CreateRemoval(getExplicitSpecRange());
}

FixItHint Hint = FixItHint::CreateRemoval(SCLoc);
S.Diag(SCLoc, diag::err_friend_decl_spec)
<< Keyword << Hint;

FS_virtual_specified = FS_explicit_specified = false;
FS_virtual_specified = false;
FS_explicit_specifier = ExplicitSpecifier();
FS_virtualLoc = FS_explicitLoc = SourceLocation();
}

Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaCodeComplete.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4970,7 +4970,8 @@ QualType Sema::ProduceConstructorSignatureHelp(Scope *S, QualType Type,
AddOverloadCandidate(FD, DeclAccessPair::make(FD, C->getAccess()), Args,
CandidateSet,
/*SuppressUsedConversions=*/false,
/*PartialOverloading=*/true);
/*PartialOverloading=*/true,
/*AllowExplicit*/ true);
} else if (auto *FTD = dyn_cast<FunctionTemplateDecl>(C)) {
AddTemplateOverloadCandidate(
FTD, DeclAccessPair::make(FTD, C->getAccess()),
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5725,7 +5725,7 @@ void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) {
Diag(DS.getVirtualSpecLoc(),
diag::err_virtual_non_function);

if (DS.isExplicitSpecified())
if (DS.hasExplicitSpecifier())
Diag(DS.getExplicitSpecLoc(),
diag::err_explicit_non_function);

Expand Down Expand Up @@ -7989,7 +7989,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
return NewFD;
}

bool isExplicit = D.getDeclSpec().isExplicitSpecified();
ExplicitSpecifier ExplicitSpecifier = D.getDeclSpec().getExplicitSpecifier();
bool isConstexpr = D.getDeclSpec().isConstexprSpecified();

// Check that the return type is not an abstract class type.
Expand All @@ -8009,7 +8009,7 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
R = SemaRef.CheckConstructorDeclarator(D, R, SC);
return CXXConstructorDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
TInfo, isExplicit, isInline,
TInfo, ExplicitSpecifier, isInline,
/*isImplicitlyDeclared=*/false, isConstexpr);

} else if (Name.getNameKind() == DeclarationName::CXXDestructorName) {
Expand Down Expand Up @@ -8054,13 +8054,13 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
IsVirtualOkay = true;
return CXXConversionDecl::Create(
SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R,
TInfo, isInline, isExplicit, isConstexpr, SourceLocation());
TInfo, isInline, ExplicitSpecifier, isConstexpr, SourceLocation());

} else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) {
SemaRef.CheckDeductionGuideDeclarator(D, R, SC);

return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(),
isExplicit, NameInfo, R, TInfo,
ExplicitSpecifier, NameInfo, R, TInfo,
D.getEndLoc());
} else if (DC->isRecord()) {
// If the name of the function is the same as the name of the record,
Expand Down Expand Up @@ -8421,7 +8421,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (getLangOpts().CPlusPlus) {
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool isExplicit = D.getDeclSpec().isExplicitSpecified();
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
bool isConstexpr = D.getDeclSpec().isConstexprSpecified();
isFriend = D.getDeclSpec().isFriendSpecified();
if (isFriend && !isInline && D.isFunctionDefinition()) {
Expand Down Expand Up @@ -8604,20 +8604,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// The explicit specifier shall be used only in the declaration of a
// constructor or conversion function within its class definition;
// see 12.3.1 and 12.3.2.
if (isExplicit && !NewFD->isInvalidDecl() &&
if (hasExplicit && !NewFD->isInvalidDecl() &&
!isa<CXXDeductionGuideDecl>(NewFD)) {
if (!CurContext->isRecord()) {
// 'explicit' was specified outside of the class.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_out_of_class)
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
} else if (!isa<CXXConstructorDecl>(NewFD) &&
!isa<CXXConversionDecl>(NewFD)) {
// 'explicit' was specified on a function that wasn't a constructor
// or conversion function.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_non_ctor_or_conv_function)
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecRange());
}
}

Expand Down
59 changes: 41 additions & 18 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,14 +657,13 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
Invalid = true;
}

// FIXME: It's not clear what should happen if multiple declarations of a
// deduction guide have different explicitness. For now at least we simply
// reject any case where the explicitness changes.
auto *NewGuide = dyn_cast<CXXDeductionGuideDecl>(New);
if (NewGuide && NewGuide->isExplicitSpecified() !=
cast<CXXDeductionGuideDecl>(Old)->isExplicitSpecified()) {
Diag(New->getLocation(), diag::err_deduction_guide_explicit_mismatch)
<< NewGuide->isExplicitSpecified();
// C++17 [temp.deduct.guide]p3:
// Two deduction guide declarations in the same translation unit
// for the same class template shall not have equivalent
// parameter-declaration-clauses.
if (isa<CXXDeductionGuideDecl>(New) &&
!New->isFunctionTemplateSpecialization()) {
Diag(New->getLocation(), diag::err_deduction_guide_redeclared);
Diag(Old->getLocation(), diag::note_previous_declaration);
}

Expand Down Expand Up @@ -8594,12 +8593,12 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R,
R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo());

// C++0x explicit conversion operators.
if (DS.isExplicitSpecified())
if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus2a)
Diag(DS.getExplicitSpecLoc(),
getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_explicit_conversion_functions
: diag::ext_explicit_conversion_functions)
<< SourceRange(DS.getExplicitSpecLoc());
<< SourceRange(DS.getExplicitSpecRange());
}

/// ActOnConversionDeclarator - Called by ActOnDeclarator to complete
Expand Down Expand Up @@ -10822,6 +10821,28 @@ struct ComputingExceptionSpec {
};
}

bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) {
llvm::APSInt Result;
ExprResult Converted = CheckConvertedConstantExpression(
ExplicitSpec.getExpr(), Context.BoolTy, Result, CCEK_ExplicitBool);
ExplicitSpec.setExpr(Converted.get());
if (Converted.isUsable() && !Converted.get()->isValueDependent()) {
ExplicitSpec.setKind(Result.getBoolValue()
? ExplicitSpecKind::ResolvedTrue
: ExplicitSpecKind::ResolvedFalse);
return true;
}
ExplicitSpec.setKind(ExplicitSpecKind::Unresolved);
return false;
}

ExplicitSpecifier Sema::ActOnExplicitBoolSpecifier(Expr *ExplicitExpr) {
ExplicitSpecifier ES(ExplicitExpr, ExplicitSpecKind::Unresolved);
if (!ExplicitExpr->isTypeDependent())
tryResolveExplicitSpecifier(ES);
return ES;
}

static Sema::ImplicitExceptionSpecification
ComputeDefaultedSpecialMemberExceptionSpec(
Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM,
Expand Down Expand Up @@ -10970,9 +10991,9 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
= Context.DeclarationNames.getCXXConstructorName(ClassType);
DeclarationNameInfo NameInfo(Name, ClassLoc);
CXXConstructorDecl *DefaultCon = CXXConstructorDecl::Create(
Context, ClassDecl, ClassLoc, NameInfo, /*Type*/QualType(),
/*TInfo=*/nullptr, /*isExplicit=*/false, /*isInline=*/true,
/*isImplicitlyDeclared=*/true, Constexpr);
Context, ClassDecl, ClassLoc, NameInfo, /*Type*/ QualType(),
/*TInfo=*/nullptr, ExplicitSpecifier(),
/*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr);
DefaultCon->setAccess(AS_public);
DefaultCon->setDefaulted();

Expand Down Expand Up @@ -11091,7 +11112,7 @@ Sema::findInheritingConstructor(SourceLocation Loc,

CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
BaseCtor->isExplicit(), /*Inline=*/true,
BaseCtor->getExplicitSpecifier(), /*Inline=*/true,
/*ImplicitlyDeclared=*/true, Constexpr,
InheritedConstructor(Shadow, BaseCtor));
if (Shadow->isInvalidDecl())
Expand Down Expand Up @@ -12543,8 +12564,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
// member of its class.
CXXConstructorDecl *CopyConstructor = CXXConstructorDecl::Create(
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
Constexpr);
ExplicitSpecifier(),
/*isInline=*/true,
/*isImplicitlyDeclared=*/true, Constexpr);
CopyConstructor->setAccess(AS_public);
CopyConstructor->setDefaulted();

Expand Down Expand Up @@ -12673,8 +12695,9 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
// member of its class.
CXXConstructorDecl *MoveConstructor = CXXConstructorDecl::Create(
Context, ClassDecl, ClassLoc, NameInfo, QualType(), /*TInfo=*/nullptr,
/*isExplicit=*/false, /*isInline=*/true, /*isImplicitlyDeclared=*/true,
Constexpr);
ExplicitSpecifier(),
/*isInline=*/true,
/*isImplicitlyDeclared=*/true, Constexpr);
MoveConstructor->setAccess(AS_public);
MoveConstructor->setDefaulted();

Expand Down
91 changes: 50 additions & 41 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3763,9 +3763,10 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
hasCopyOrMoveCtorParam(S.Context, Info));

if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Args,
CandidateSet, SuppressUserConversions);
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Args, CandidateSet, SuppressUserConversions,
/*PartialOverloading=*/false, AllowExplicit);
else {
// C++ [over.match.copy]p1:
// - When initializing a temporary to be bound to the first parameter
Expand All @@ -3779,8 +3780,8 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
hasCopyOrMoveCtorParam(S.Context, Info);
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
CandidateSet, SuppressUserConversions,
/*PartialOverloading=*/false,
/*AllowExplicit=*/AllowExplicitConv);
/*PartialOverloading=*/false, AllowExplicit,
AllowExplicitConv);
}
}

Expand Down Expand Up @@ -3813,16 +3814,17 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
else
Conv = cast<CXXConversionDecl>(D);

if ((AllowExplicit && !CopyInitializing) || !Conv->isExplicit()) {
if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
ActingDC, Initializer, DestType,
CandidateSet, AllowExplicit,
/*AllowResultConversion*/false);
S.AddTemplateConversionCandidate(
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
CandidateSet, AllowExplicit, AllowExplicit,
/*AllowResultConversion*/ false);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
DestType, CandidateSet, AllowExplicit,
/*AllowResultConversion*/false);
AllowExplicit,
/*AllowResultConversion*/ false);
}
}
}
Expand Down Expand Up @@ -4368,14 +4370,16 @@ static OverloadingResult TryRefInitWithConversionFunction(
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicitCtors);
else
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
S.AddOverloadCandidate(
Info.Constructor, Info.FoundDecl, Initializer, CandidateSet,
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicitCtors);
}
}
}
Expand Down Expand Up @@ -4410,17 +4414,17 @@ static OverloadingResult TryRefInitWithConversionFunction(
// candidates with reference-compatible results? That might be needed to
// break recursion.
if ((AllowExplicitConvs || !Conv->isExplicit()) &&
(AllowRValues || Conv->getConversionType()->isLValueReferenceType())){
(AllowRValues ||
Conv->getConversionType()->isLValueReferenceType())) {
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
ActingDC, Initializer,
DestType, CandidateSet,
/*AllowObjCConversionOnExplicit=*/
false);
S.AddTemplateConversionCandidate(
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
CandidateSet,
/*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
Initializer, DestType, CandidateSet,
/*AllowObjCConversionOnExplicit=*/false);
S.AddConversionCandidate(
Conv, I.getPair(), ActingDC, Initializer, DestType, CandidateSet,
/*AllowObjCConversionOnExplicit=*/false, AllowExplicitConvs);
}
}
}
Expand Down Expand Up @@ -4996,14 +5000,16 @@ static void TryUserDefinedConversion(Sema &S,
if (!Info.Constructor->isInvalidDecl() &&
Info.Constructor->isConvertingConstructor(AllowExplicit)) {
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
S.AddTemplateOverloadCandidate(
Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Initializer, CandidateSet,
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicit);
else
S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
/*SuppressUserConversions=*/true,
/*PartialOverloading*/ false, AllowExplicit);
}
}
}
Expand Down Expand Up @@ -5038,12 +5044,12 @@ static void TryUserDefinedConversion(Sema &S,

if (AllowExplicit || !Conv->isExplicit()) {
if (ConvTemplate)
S.AddTemplateConversionCandidate(ConvTemplate, I.getPair(),
ActingDC, Initializer, DestType,
CandidateSet, AllowExplicit);
S.AddTemplateConversionCandidate(
ConvTemplate, I.getPair(), ActingDC, Initializer, DestType,
CandidateSet, AllowExplicit, AllowExplicit);
else
S.AddConversionCandidate(Conv, I.getPair(), ActingDC,
Initializer, DestType, CandidateSet,
S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer,
DestType, CandidateSet, AllowExplicit,
AllowExplicit);
}
}
Expand Down Expand Up @@ -9336,6 +9342,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
OverloadCandidateSet::iterator Best;

bool HasAnyDeductionGuide = false;
bool AllowExplicit = !Kind.isCopyInit() || ListInit;

auto tryToResolveOverload =
[&](bool OnlyListConstructors) -> OverloadingResult {
Expand All @@ -9361,7 +9368,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// converting constructors (12.3.1) of that class.
// C++ [over.match.copy]p1: (non-list copy-initialization from class)
// The converting constructors of T are candidate functions.
if (Kind.isCopyInit() && !ListInit) {
if (!AllowExplicit) {
// Only consider converting constructors.
if (GD->isExplicit())
continue;
Expand Down Expand Up @@ -9396,11 +9403,13 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(

if (TD)
AddTemplateOverloadCandidate(TD, I.getPair(), /*ExplicitArgs*/ nullptr,
Inits, Candidates,
SuppressUserConversions);
Inits, Candidates, SuppressUserConversions,
/*PartialOverloading*/ false,
AllowExplicit);
else
AddOverloadCandidate(GD, I.getPair(), Inits, Candidates,
SuppressUserConversions);
SuppressUserConversions,
/*PartialOverloading*/ false, AllowExplicit);
}
return Candidates.BestViableFunction(*this, Kind.getLocation(), Best);
};
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1325,7 +1325,7 @@ static void addFunctionPointerConversion(Sema &S,
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
S.Context, Class, Loc,
DeclarationNameInfo(ConversionName, Loc, ConvNameLoc), ConvTy, ConvTSI,
/*isInline=*/true, /*isExplicit=*/false,
/*isInline=*/true, ExplicitSpecifier(),
/*isConstexpr=*/S.getLangOpts().CPlusPlus17,
CallOperator->getBody()->getEndLoc());
Conversion->setAccess(AS_public);
Expand Down Expand Up @@ -1412,7 +1412,7 @@ static void addBlockPointerConversion(Sema &S,
CXXConversionDecl *Conversion = CXXConversionDecl::Create(
S.Context, Class, Loc, DeclarationNameInfo(Name, Loc, NameLoc), ConvTy,
S.Context.getTrivialTypeSourceInfo(ConvTy, Loc),
/*isInline=*/true, /*isExplicit=*/false,
/*isInline=*/true, ExplicitSpecifier(),
/*isConstexpr=*/false, CallOperator->getBody()->getEndLoc());
Conversion->setAccess(AS_public);
Conversion->setImplicit(true);
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3041,10 +3041,11 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD,
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else if (CtorInfo)
AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
llvm::makeArrayRef(&Arg, NumArgs), OCS,
/*SuppressUserConversions*/ true);
else
AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
true);
/*SuppressUserConversions*/ true);
} else if (FunctionTemplateDecl *Tmpl =
dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
Expand Down
171 changes: 108 additions & 63 deletions clang/lib/Sema/SemaOverload.cpp

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (DS.isVirtualSpecified())
EmitDiag(DS.getVirtualSpecLoc());

if (DS.isExplicitSpecified())
if (DS.hasExplicitSpecifier())
EmitDiag(DS.getExplicitSpecLoc());

if (DS.isNoreturnSpecified())
Expand Down Expand Up @@ -1836,8 +1836,8 @@ struct ConvertConstructorToDeductionGuideTransform {
return nullptr;
TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType);

return buildDeductionGuide(TemplateParams, CD->isExplicit(), NewTInfo,
CD->getBeginLoc(), CD->getLocation(),
return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(),
NewTInfo, CD->getBeginLoc(), CD->getLocation(),
CD->getEndLoc());
}

Expand Down Expand Up @@ -1866,8 +1866,8 @@ struct ConvertConstructorToDeductionGuideTransform {
Params.push_back(NewParam);
}

return buildDeductionGuide(Template->getTemplateParameters(), false, TSI,
Loc, Loc, Loc);
return buildDeductionGuide(Template->getTemplateParameters(),
ExplicitSpecifier(), TSI, Loc, Loc, Loc);
}

private:
Expand Down Expand Up @@ -2017,7 +2017,7 @@ struct ConvertConstructorToDeductionGuideTransform {
}

NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams,
bool Explicit, TypeSourceInfo *TInfo,
ExplicitSpecifier ES, TypeSourceInfo *TInfo,
SourceLocation LocStart, SourceLocation Loc,
SourceLocation LocEnd) {
DeclarationNameInfo Name(DeductionGuideName, Loc);
Expand All @@ -2026,8 +2026,8 @@ struct ConvertConstructorToDeductionGuideTransform {

// Build the implicit deduction guide template.
auto *Guide =
CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, Explicit,
Name, TInfo->getType(), TInfo, LocEnd);
CXXDeductionGuideDecl::Create(SemaRef.Context, DC, LocStart, ES, Name,
TInfo->getType(), TInfo, LocEnd);
Guide->setImplicit();
Guide->setParams(Params);

Expand Down
53 changes: 45 additions & 8 deletions clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,29 @@ static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr(
Attr.getSpellingListIndex());
}

static ExplicitSpecifier
instantiateExplicitSpecifier(Sema &S,
const MultiLevelTemplateArgumentList &TemplateArgs,
ExplicitSpecifier ES, FunctionDecl *New) {
if (!ES.getExpr())
return ES;
Expr *OldCond = ES.getExpr();
Expr *Cond = nullptr;
{
EnterExpressionEvaluationContext Unevaluated(
S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
ExprResult SubstResult = S.SubstExpr(OldCond, TemplateArgs);
if (SubstResult.isInvalid()) {
return ExplicitSpecifier::Invalid();
}
Cond = SubstResult.get();
}
ExplicitSpecifier Result(Cond, ES.getKind());
if (!Cond->isTypeDependent())
S.tryResolveExplicitSpecifier(Result);
return Result;
}

static void instantiateDependentAMDGPUWavesPerEUAttr(
Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
const AMDGPUWavesPerEUAttr &Attr, Decl *New) {
Expand Down Expand Up @@ -1690,6 +1713,14 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
cast<Decl>(Owner)->isDefinedOutsideFunctionOrMethod());
LocalInstantiationScope Scope(SemaRef, MergeWithParentScope);

ExplicitSpecifier InstantiatedExplicitSpecifier;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
InstantiatedExplicitSpecifier = instantiateExplicitSpecifier(
SemaRef, TemplateArgs, DGuide->getExplicitSpecifier(), DGuide);
if (InstantiatedExplicitSpecifier.isInvalid())
return nullptr;
}

SmallVector<ParmVarDecl *, 4> Params;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
Expand Down Expand Up @@ -1727,8 +1758,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
FunctionDecl *Function;
if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) {
Function = CXXDeductionGuideDecl::Create(
SemaRef.Context, DC, D->getInnerLocStart(), DGuide->isExplicit(),
NameInfo, T, TInfo, D->getSourceRange().getEnd());
SemaRef.Context, DC, D->getInnerLocStart(),
InstantiatedExplicitSpecifier, NameInfo, T, TInfo,
D->getSourceRange().getEnd());
if (DGuide->isCopyDeductionCandidate())
cast<CXXDeductionGuideDecl>(Function)->setIsCopyDeductionCandidate();
Function->setAccess(D->getAccess());
Expand Down Expand Up @@ -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;
TypeSourceInfo *TInfo = SubstFunctionType(D, Params);
if (!TInfo)
Expand Down Expand Up @@ -2035,11 +2073,10 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
DeclarationNameInfo NameInfo
= SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs);
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
Method = CXXConstructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
false, Constructor->isConstexpr());
Method = CXXConstructorDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false,
Constructor->isConstexpr());
Method->setRangeEnd(Constructor->getEndLoc());
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
Expand All @@ -2050,7 +2087,7 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(
} else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) {
Method = CXXConversionDecl::Create(
SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo,
Conversion->isInlineSpecified(), Conversion->isExplicit(),
Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier,
Conversion->isConstexpr(), Conversion->getEndLoc());
} else {
StorageClass SC = D->isStatic() ? SC_Static : SC_None;
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,6 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) {
FD->setStorageClass(static_cast<StorageClass>(Record.readInt()));
FD->setInlineSpecified(Record.readInt());
FD->setImplicitlyInline(Record.readInt());
FD->setExplicitSpecified(Record.readInt());
FD->setVirtualAsWritten(Record.readInt());
FD->setPure(Record.readInt());
FD->setHasInheritedPrototype(Record.readInt());
Expand Down Expand Up @@ -1977,6 +1976,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) {
}

void ASTDeclReader::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
D->setExplicitSpecifier(Record.readExplicitSpec());
VisitFunctionDecl(D);
D->setIsCopyDeductionCandidate(Record.readInt());
}
Expand All @@ -2002,6 +2002,7 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) {
void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
// We need the inherited constructor information to merge the declaration,
// so we have to read it before we call VisitCXXMethodDecl.
D->setExplicitSpecifier(Record.readExplicitSpec());
if (D->isInheritingConstructor()) {
auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>();
auto *Ctor = ReadDeclAs<CXXConstructorDecl>();
Expand All @@ -2027,6 +2028,7 @@ void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
}

void ASTDeclReader::VisitCXXConversionDecl(CXXConversionDecl *D) {
D->setExplicitSpecifier(Record.readExplicitSpec());
VisitCXXMethodDecl(D);
}

Expand Down Expand Up @@ -3750,10 +3752,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
D = CXXMethodDecl::CreateDeserialized(Context, ID);
break;
case DECL_CXX_CONSTRUCTOR:
D = CXXConstructorDecl::CreateDeserialized(Context, ID, false);
break;
case DECL_CXX_INHERITED_CONSTRUCTOR:
D = CXXConstructorDecl::CreateDeserialized(Context, ID, true);
D = CXXConstructorDecl::CreateDeserialized(Context, ID, Record.readInt());
break;
case DECL_CXX_DESTRUCTOR:
D = CXXDestructorDecl::CreateDeserialized(Context, ID);
Expand Down
1 change: 0 additions & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1277,7 +1277,6 @@ void ASTWriter::WriteBlockInfoBlock() {
RECORD(DECL_CXX_RECORD);
RECORD(DECL_CXX_METHOD);
RECORD(DECL_CXX_CONSTRUCTOR);
RECORD(DECL_CXX_INHERITED_CONSTRUCTOR);
RECORD(DECL_CXX_DESTRUCTOR);
RECORD(DECL_CXX_CONVERSION);
RECORD(DECL_ACCESS_SPEC);
Expand Down
24 changes: 15 additions & 9 deletions clang/lib/Serialization/ASTWriterDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,6 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Record.push_back(static_cast<int>(D->getStorageClass())); // FIXME: stable encoding
Record.push_back(D->isInlineSpecified());
Record.push_back(D->isInlined());
Record.push_back(D->isExplicitSpecified());
Record.push_back(D->isVirtualAsWritten());
Record.push_back(D->isPure());
Record.push_back(D->hasInheritedPrototype());
Expand Down Expand Up @@ -638,7 +637,18 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) {
Code = serialization::DECL_FUNCTION;
}

static void addExplicitSpecifier(ExplicitSpecifier ES,
ASTRecordWriter &Record) {
uint64_t Kind = static_cast<uint64_t>(ES.getKind());
Kind = Kind << 1 | static_cast<bool>(ES.getExpr());
Record.push_back(Kind);
if (ES.getExpr()) {
Record.AddStmt(ES.getExpr());
}
}

void ASTDeclWriter::VisitCXXDeductionGuideDecl(CXXDeductionGuideDecl *D) {
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
VisitFunctionDecl(D);
Record.push_back(D->isCopyDeductionCandidate());
Code = serialization::DECL_CXX_DEDUCTION_GUIDE;
Expand Down Expand Up @@ -1331,19 +1341,15 @@ void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) {
}

void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
Record.push_back(D->getTraillingAllocKind());
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
if (auto Inherited = D->getInheritedConstructor()) {
Record.AddDeclRef(Inherited.getShadowDecl());
Record.AddDeclRef(Inherited.getConstructor());
Code = serialization::DECL_CXX_INHERITED_CONSTRUCTOR;
} else {
Code = serialization::DECL_CXX_CONSTRUCTOR;
}

VisitCXXMethodDecl(D);

Code = D->isInheritingConstructor()
? serialization::DECL_CXX_INHERITED_CONSTRUCTOR
: serialization::DECL_CXX_CONSTRUCTOR;
Code = serialization::DECL_CXX_CONSTRUCTOR;
}

void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
Expand All @@ -1357,6 +1363,7 @@ void ASTDeclWriter::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
}

void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) {
addExplicitSpecifier(D->getExplicitSpecifier(), Record);
VisitCXXMethodDecl(D);
Code = serialization::DECL_CXX_CONVERSION;
}
Expand Down Expand Up @@ -2156,7 +2163,6 @@ void ASTWriter::WriteDeclAbbrevs() {
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 3)); // StorageClass
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Inline
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // InlineSpecified
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // ExplicitSpecified
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // VirtualAsWritten
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Pure
Abv->Add(BitCodeAbbrevOp(0)); // HasInheritedProto
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/temp/temp.deduct.guide/p1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ extern A(int(&)[26]) -> A<int>;
#endif
mutable A(int(&)[27]) -> A<int>; // expected-error-re {{{{'mutable' cannot be applied to|illegal storage class on}} function}}
virtual A(int(&)[28]) -> A<int>; // expected-error {{'virtual' can only appear on non-static member functions}}
const A(int(&)[28]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}}
const A(int(&)[31]) -> A<int>; // expected-error {{deduction guide cannot be declared 'const'}}

const volatile static constexpr inline A(int(&)[29]) -> A<int>; // expected-error {{deduction guide cannot be declared 'static inline constexpr const volatile'}}

Expand Down
8 changes: 4 additions & 4 deletions clang/test/CXX/temp/temp.deduct.guide/p3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
// The same restrictions apply to the parameter-declaration-clause of a
// deduction guide as in a function declaration.
template<typename T> struct A {};
A(void) -> A<int>; // ok
A(void) -> A<int>; // expected-note {{previous}}
A(void, int) -> A<int>; // expected-error {{'void' must be the first and only parameter if specified}}

// We interpret this as also extending to the validity of redeclarations. It's
// a bit of a stretch (OK, a lot of a stretch) but it gives desirable answers.
A() -> A<int>; // ok, redeclaration
A() -> A<int>; // expected-error {{redeclaration of deduction guide}}
// expected-note@-1 {{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}}

template<typename T> A(T) -> A<typename T::foo>;
Expand Down
124 changes: 124 additions & 0 deletions clang/test/PCH/cxx-explicit-specifier.cpp
Original file line number Diff line number Diff line change
@@ -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

}
2 changes: 1 addition & 1 deletion clang/test/SemaCXX/builtin-is-constant-evaluated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static_assert(&r == &x);

#if defined(__cpp_conditional_explicit)
struct TestConditionalExplicit {
explicit(__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
explicit(!__builtin_is_constant_evaluated()) TestConditionalExplicit(int) {}
};
TestConditionalExplicit e = 42;
#endif
20 changes: 20 additions & 0 deletions clang/test/SemaCXX/cxx2a-compat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {{no viable conversion from 'const char8_t [9]' to 'string'}}
#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
719 changes: 719 additions & 0 deletions clang/test/SemaCXX/cxx2a-explicit-bool.cpp

Large diffs are not rendered by default.

23 changes: 21 additions & 2 deletions clang/test/SemaCXX/explicit.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s

namespace Constructor {
struct A {
A(int);
Expand Down Expand Up @@ -34,6 +36,21 @@ B &&b3(0); // expected-error {{could not bind}}
B b4{0};
B &&b5 = {0}; // expected-error {{chosen constructor is explicit}}
B &&b6{0};

struct S {
template <bool b = true>
explicit S();
};

struct T : S {
// T();
};

struct U : T {
U();
};
U::U() {}

}

namespace Conversion {
Expand Down Expand Up @@ -183,7 +200,8 @@ namespace Conversion {
const int &copyList7 = {b};
const int &copyList8 = {n}; // expected-error {{no viable conversion}}
}


#if __cplusplus < 201707L
void testNew()
{
// 5.3.4p6:
Expand All @@ -200,7 +218,8 @@ namespace Conversion {
new int[i];
new int[ni]; // expected-error {{array size expression of type 'NotInt' requires explicit conversion to type 'int'}}
}

#endif

void testDelete()
{
// 5.3.5pp2:
Expand Down
3 changes: 3 additions & 0 deletions clang/unittests/AST/Language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ ArgVector getBasicRunOptionsForLanguage(Language Lang) {
case Lang_CXX14:
BasicArgs = {"-std=c++14", "-frtti"};
break;
case Lang_CXX2a:
BasicArgs = {"-std=c++2a", "-frtti"};
break;
case Lang_OpenCL:
case Lang_OBJCXX:
llvm_unreachable("Not implemented yet!");
Expand Down
1 change: 1 addition & 0 deletions clang/unittests/AST/Language.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum Language {
Lang_CXX,
Lang_CXX11,
Lang_CXX14,
Lang_CXX2a,
Lang_OpenCL,
Lang_OBJCXX
};
Expand Down
4 changes: 4 additions & 0 deletions clang/unittests/AST/MatchVerifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ testing::AssertionResult MatchVerifier<NodeType>::match(
Args.push_back("-std=c++14");
FileName = "input.cc";
break;
case Lang_CXX2a:
Args.push_back("-std=c++2a");
FileName = "input.cc";
break;
case Lang_OpenCL:
FileName = "input.cl";
break;
Expand Down
40 changes: 40 additions & 0 deletions clang/unittests/AST/StructuralEquivalenceTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,26 @@ TEST_F(StructuralEquivalenceTest, CompareSameDeclWithMultiple) {
EXPECT_FALSE(testStructuralMatch(t));
}

TEST_F(StructuralEquivalenceTest, ExplicitBoolDifferent) {
auto Decls = makeNamedDecls("struct foo {explicit(false) foo(int);};",
"struct foo {explicit(true) foo(int);};", Lang_CXX2a);
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
get<0>(Decls), cxxConstructorDecl(hasName("foo")));
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
get<1>(Decls), cxxConstructorDecl(hasName("foo")));
EXPECT_FALSE(testStructuralMatch(First, Second));
}

TEST_F(StructuralEquivalenceTest, ExplicitBoolSame) {
auto Decls = makeNamedDecls("struct foo {explicit(true) foo(int);};",
"struct foo {explicit(true) foo(int);};", Lang_CXX2a);
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
get<0>(Decls), cxxConstructorDecl(hasName("foo")));
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
get<1>(Decls), cxxConstructorDecl(hasName("foo")));
EXPECT_TRUE(testStructuralMatch(First, Second));
}

struct StructuralEquivalenceEnumTest : StructuralEquivalenceTest {};

TEST_F(StructuralEquivalenceEnumTest, FwdDeclEnumShouldBeEqualWithFwdDeclEnum) {
Expand Down Expand Up @@ -853,5 +873,25 @@ TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
EXPECT_FALSE(testStructuralMatch(t));
}

TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
"template <bool b> struct foo {explicit(b) foo(int);};", Lang_CXX2a);
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
EXPECT_TRUE(testStructuralMatch(First, Second));
}

TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolDifference) {
auto Decls = makeNamedDecls("template <bool b> struct foo {explicit(b) foo(int);};",
"template <bool b> struct foo {explicit(!b) foo(int);};", Lang_CXX2a);
CXXConstructorDecl *First = FirstDeclMatcher<CXXConstructorDecl>().match(
get<0>(Decls), cxxConstructorDecl(hasName("foo<b>")));
CXXConstructorDecl *Second = FirstDeclMatcher<CXXConstructorDecl>().match(
get<1>(Decls), cxxConstructorDecl(hasName("foo<b>")));
EXPECT_FALSE(testStructuralMatch(First, Second));
}

} // end namespace ast_matchers
} // end namespace clang
2 changes: 1 addition & 1 deletion clang/www/cxx_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -1002,7 +1002,7 @@ <h2 id="cxx20">C++2a implementation status</h2>
<tr>
<td><tt>explicit(bool)</tt></td>
<td><a href="http://wg21.link/p0892r2">P0892R2</a></td>
<td class="none" align="center">No</td>
<td class="svn" align="center">SVN</td>
</tr>
<!-- San Diego papers -->
<tr>
Expand Down