[clang] 0dfb43d - Fix handling of default arguments in __attribute__((enable_if)).
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu May 28 15:35:32 PDT 2020
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}}
+}
More information about the cfe-commits
mailing list