Author: Richard Smith Date: 2020-05-28T15:35:22-07:00 New Revision: 0dfb43deb6d5511a8ea69eeb7373a212ebd6c9c1
URL: https://github.com/llvm/llvm-project/commit/0dfb43deb6d5511a8ea69eeb7373a212ebd6c9c1 DIFF: https://github.com/llvm/llvm-project/commit/0dfb43deb6d5511a8ea69eeb7373a212ebd6c9c1.diff LOG: 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. Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaExpr.cpp clang/lib/Sema/SemaOverload.cpp clang/test/SemaCXX/enable_if.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index e63f65e2580c..dc7ee2ddd0b8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3371,7 +3371,8 @@ class Sema final { /// 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 diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 261e69b44052..4063289711cc 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -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 diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 1b00b2b18572..ad75529debdb 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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(); diff --git a/clang/test/SemaCXX/enable_if.cpp b/clang/test/SemaCXX/enable_if.cpp index 37664276e470..50d898959c45 100644 --- a/clang/test/SemaCXX/enable_if.cpp +++ b/clang/test/SemaCXX/enable_if.cpp @@ -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}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits