forked from OSchip/llvm-project
[Concepts] Check function constraints before deducing auto return type
A constrained function with an auto return type would have it's definition instantiated in order to deduce the auto return type before the constraints are checked. Move the constraints check after the return type deduction.
This commit is contained in:
parent
5ae6554a1d
commit
980517b353
|
@ -245,8 +245,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
|||
return true;
|
||||
}
|
||||
|
||||
// See if this is a deleted function.
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
// See if this is a deleted function.
|
||||
if (FD->isDeleted()) {
|
||||
auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
|
||||
if (Ctor && Ctor->isInheritingConstructor())
|
||||
|
@ -259,6 +259,29 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
|||
return true;
|
||||
}
|
||||
|
||||
// [expr.prim.id]p4
|
||||
// A program that refers explicitly or implicitly to a function with a
|
||||
// trailing requires-clause whose constraint-expression is not satisfied,
|
||||
// other than to declare it, is ill-formed. [...]
|
||||
//
|
||||
// See if this is a function with constraints that need to be satisfied.
|
||||
// Check this before deducing the return type, as it might instantiate the
|
||||
// definition.
|
||||
if (FD->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (CheckFunctionConstraints(FD, Satisfaction, Loc))
|
||||
// A diagnostic will have already been generated (non-constant
|
||||
// constraint expression, for example)
|
||||
return true;
|
||||
if (!Satisfaction.IsSatisfied) {
|
||||
Diag(Loc,
|
||||
diag::err_reference_to_function_with_unsatisfied_constraints)
|
||||
<< D;
|
||||
DiagnoseUnsatisfiedConstraint(Satisfaction);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the function has a deduced return type, and we can't deduce it,
|
||||
// then we can't use it either.
|
||||
if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() &&
|
||||
|
@ -326,29 +349,6 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs,
|
|||
|
||||
diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc);
|
||||
|
||||
// [expr.prim.id]p4
|
||||
// A program that refers explicitly or implicitly to a function with a
|
||||
// trailing requires-clause whose constraint-expression is not satisfied,
|
||||
// other than to declare it, is ill-formed. [...]
|
||||
//
|
||||
// See if this is a function with constraints that need to be satisfied.
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
|
||||
if (FD->getTrailingRequiresClause()) {
|
||||
ConstraintSatisfaction Satisfaction;
|
||||
if (CheckFunctionConstraints(FD, Satisfaction, Loc))
|
||||
// A diagnostic will have already been generated (non-constant
|
||||
// constraint expression, for example)
|
||||
return true;
|
||||
if (!Satisfaction.IsSatisfied) {
|
||||
Diag(Loc,
|
||||
diag::err_reference_to_function_with_unsatisfied_constraints)
|
||||
<< D;
|
||||
DiagnoseUnsatisfiedConstraint(Satisfaction);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) &&
|
||||
!isUnevaluatedContext()) {
|
||||
// C++ [expr.prim.req.nested] p3
|
||||
|
|
|
@ -26,11 +26,14 @@ namespace methods
|
|||
struct A {
|
||||
static void foo(int) requires (sizeof(T) == 1) {} // expected-note 3{{because 'sizeof(char [2]) == 1' (2 == 1) evaluated to false}}
|
||||
static void bar(int) requires (sizeof(T) == 2) {} // expected-note 3{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
|
||||
// Make sure the function body is not instantiated before constraints are checked.
|
||||
static auto baz(int) requires (sizeof(T) == 2) { return T::foo(); } // expected-note{{because 'sizeof(char) == 2' (1 == 2) evaluated to false}}
|
||||
};
|
||||
|
||||
void baz() {
|
||||
A<char>::foo(1);
|
||||
A<char>::bar(1); // expected-error{{invalid reference to function 'bar': constraints not satisfied}}
|
||||
A<char>::baz(1); // expected-error{{invalid reference to function 'baz': constraints not satisfied}}
|
||||
A<char[2]>::foo(1); // expected-error{{invalid reference to function 'foo': constraints not satisfied}}
|
||||
A<char[2]>::bar(1);
|
||||
void (*p1)(int) = A<char>::foo;
|
||||
|
|
Loading…
Reference in New Issue