forked from OSchip/llvm-project
Fix handling of default arguments in __attribute__((enable_if)).
We didn't properly build default argument expressions previously -- we failed to build the wrapper CXXDefaultArgExpr node, which meant that std::source_location misbehaved, and we didn't perform default argument instantiation when necessary, which meant that dependent default arguments in function templates didn't work at all.
This commit is contained in:
parent
b0b2507717
commit
0dfb43deb6
|
@ -3371,7 +3371,8 @@ public:
|
|||
|
||||
/// Check the enable_if expressions on the given function. Returns the first
|
||||
/// failing attribute, or NULL if they were all successful.
|
||||
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
EnableIfAttr *CheckEnableIf(FunctionDecl *Function, SourceLocation CallLoc,
|
||||
ArrayRef<Expr *> Args,
|
||||
bool MissingImplicitThis = false);
|
||||
|
||||
/// Find the failed Boolean condition within a given Boolean
|
||||
|
|
|
@ -6060,7 +6060,8 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn,
|
|||
if (Callee->getMinRequiredArguments() > ArgExprs.size())
|
||||
return;
|
||||
|
||||
if (const EnableIfAttr *Attr = S.CheckEnableIf(Callee, ArgExprs, true)) {
|
||||
if (const EnableIfAttr *Attr =
|
||||
S.CheckEnableIf(Callee, Fn->getBeginLoc(), ArgExprs, true)) {
|
||||
S.Diag(Fn->getBeginLoc(),
|
||||
isa<CXXMethodDecl>(Callee)
|
||||
? diag::err_ovl_no_viable_member_function_in_call
|
||||
|
|
|
@ -6356,7 +6356,8 @@ void Sema::AddOverloadCandidate(
|
|||
}
|
||||
}
|
||||
|
||||
if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) {
|
||||
if (EnableIfAttr *FailedAttr =
|
||||
CheckEnableIf(Function, CandidateSet.getLocation(), Args)) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_enable_if;
|
||||
Candidate.DeductionFailure.Data = FailedAttr;
|
||||
|
@ -6462,11 +6463,10 @@ Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg,
|
||||
ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap,
|
||||
bool MissingImplicitThis, Expr *&ConvertedThis,
|
||||
SmallVectorImpl<Expr *> &ConvertedArgs) {
|
||||
static bool convertArgsForAvailabilityChecks(
|
||||
Sema &S, FunctionDecl *Function, Expr *ThisArg, SourceLocation CallLoc,
|
||||
ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap, bool MissingImplicitThis,
|
||||
Expr *&ConvertedThis, SmallVectorImpl<Expr *> &ConvertedArgs) {
|
||||
if (ThisArg) {
|
||||
CXXMethodDecl *Method = cast<CXXMethodDecl>(Function);
|
||||
assert(!isa<CXXConstructorDecl>(Method) &&
|
||||
|
@ -6511,17 +6511,7 @@ convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg,
|
|||
if (!Function->isVariadic() && Args.size() < Function->getNumParams()) {
|
||||
for (unsigned i = Args.size(), e = Function->getNumParams(); i != e; ++i) {
|
||||
ParmVarDecl *P = Function->getParamDecl(i);
|
||||
Expr *DefArg = P->hasUninstantiatedDefaultArg()
|
||||
? P->getUninstantiatedDefaultArg()
|
||||
: P->getDefaultArg();
|
||||
// This can only happen in code completion, i.e. when PartialOverloading
|
||||
// is true.
|
||||
if (!DefArg)
|
||||
return false;
|
||||
ExprResult R =
|
||||
S.PerformCopyInitialization(InitializedEntity::InitializeParameter(
|
||||
S.Context, Function->getParamDecl(i)),
|
||||
SourceLocation(), DefArg);
|
||||
ExprResult R = S.BuildCXXDefaultArgExpr(CallLoc, Function, P);
|
||||
if (R.isInvalid())
|
||||
return false;
|
||||
ConvertedArgs.push_back(R.get());
|
||||
|
@ -6533,7 +6523,9 @@ convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg,
|
|||
return true;
|
||||
}
|
||||
|
||||
EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
||||
EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function,
|
||||
SourceLocation CallLoc,
|
||||
ArrayRef<Expr *> Args,
|
||||
bool MissingImplicitThis) {
|
||||
auto EnableIfAttrs = Function->specific_attrs<EnableIfAttr>();
|
||||
if (EnableIfAttrs.begin() == EnableIfAttrs.end())
|
||||
|
@ -6544,7 +6536,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
|||
// FIXME: We should look into making enable_if late-parsed.
|
||||
Expr *DiscardedThis;
|
||||
if (!convertArgsForAvailabilityChecks(
|
||||
*this, Function, /*ThisArg=*/nullptr, Args, Trap,
|
||||
*this, Function, /*ThisArg=*/nullptr, CallLoc, Args, Trap,
|
||||
/*MissingImplicitThis=*/true, DiscardedThis, ConvertedArgs))
|
||||
return *EnableIfAttrs.begin();
|
||||
|
||||
|
@ -6874,7 +6866,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl,
|
|||
}
|
||||
}
|
||||
|
||||
if (EnableIfAttr *FailedAttr = CheckEnableIf(Method, Args, true)) {
|
||||
if (EnableIfAttr *FailedAttr =
|
||||
CheckEnableIf(Method, CandidateSet.getLocation(), Args, true)) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_enable_if;
|
||||
Candidate.DeductionFailure.Data = FailedAttr;
|
||||
|
@ -7327,7 +7320,8 @@ void Sema::AddConversionCandidate(
|
|||
"Can only end up with a standard conversion sequence or failure");
|
||||
}
|
||||
|
||||
if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
|
||||
if (EnableIfAttr *FailedAttr =
|
||||
CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_enable_if;
|
||||
Candidate.DeductionFailure.Data = FailedAttr;
|
||||
|
@ -7497,7 +7491,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion,
|
|||
}
|
||||
}
|
||||
|
||||
if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) {
|
||||
if (EnableIfAttr *FailedAttr =
|
||||
CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) {
|
||||
Candidate.Viable = false;
|
||||
Candidate.FailureKind = ovl_fail_enable_if;
|
||||
Candidate.DeductionFailure.Data = FailedAttr;
|
||||
|
@ -14130,7 +14125,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
// resolution process, we still need to handle the enable_if attribute. Do
|
||||
// that here, so it will not hide previous -- and more relevant -- errors.
|
||||
if (auto *MemE = dyn_cast<MemberExpr>(NakedMemExpr)) {
|
||||
if (const EnableIfAttr *Attr = CheckEnableIf(Method, Args, true)) {
|
||||
if (const EnableIfAttr *Attr =
|
||||
CheckEnableIf(Method, LParenLoc, Args, true)) {
|
||||
Diag(MemE->getMemberLoc(),
|
||||
diag::err_ovl_no_viable_member_function_in_call)
|
||||
<< Method << Method->getSourceRange();
|
||||
|
|
|
@ -561,3 +561,15 @@ namespace IgnoreUnusedArgSideEffects {
|
|||
float &x = h();
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace DefaultArgs {
|
||||
void f(int n = __builtin_LINE()) __attribute__((enable_if(n == 12345, "only callable on line 12345"))); // expected-note {{only callable on line 12345}}
|
||||
void g() { f(); } // expected-error {{no matching function}}
|
||||
#line 12345
|
||||
void h() { f(); }
|
||||
|
||||
template<typename T> void x(int n = T()) __attribute__((enable_if(n == 0, ""))) {} // expected-note {{candidate}}
|
||||
void y() { x<int>(); }
|
||||
struct Z { constexpr operator int() const { return 1; } };
|
||||
void z() { x<Z>(); } // expected-error {{no matching function}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue