forked from OSchip/llvm-project
Improve handling of value dependent expressions in __attribute__((enable_if)), both in the condition expression and at the call site. Fixes PR20988!
llvm-svn: 224320
This commit is contained in:
parent
417fc6b303
commit
f0202ca775
|
@ -9088,7 +9088,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx,
|
|||
ArgVector ArgValues(Args.size());
|
||||
for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
|
||||
I != E; ++I) {
|
||||
if (!Evaluate(ArgValues[I - Args.begin()], Info, *I))
|
||||
if ((*I)->isValueDependent() ||
|
||||
!Evaluate(ArgValues[I - Args.begin()], Info, *I))
|
||||
// If evaluation fails, throw away the argument entirely.
|
||||
ArgValues[I - Args.begin()] = APValue();
|
||||
if (Info.EvalStatus.HasSideEffects)
|
||||
|
|
|
@ -5792,6 +5792,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
|||
// Convert the arguments.
|
||||
SmallVector<Expr *, 16> ConvertedArgs;
|
||||
bool InitializationFailed = false;
|
||||
bool ContainsValueDependentExpr = false;
|
||||
for (unsigned i = 0, e = Args.size(); i != e; ++i) {
|
||||
if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) &&
|
||||
!cast<CXXMethodDecl>(Function)->isStatic() &&
|
||||
|
@ -5804,6 +5805,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
|||
InitializationFailed = true;
|
||||
break;
|
||||
}
|
||||
ContainsValueDependentExpr |= R.get()->isValueDependent();
|
||||
ConvertedArgs.push_back(R.get());
|
||||
} else {
|
||||
ExprResult R =
|
||||
|
@ -5816,6 +5818,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
|||
InitializationFailed = true;
|
||||
break;
|
||||
}
|
||||
ContainsValueDependentExpr |= R.get()->isValueDependent();
|
||||
ConvertedArgs.push_back(R.get());
|
||||
}
|
||||
}
|
||||
|
@ -5826,9 +5829,16 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
|
|||
for (AttrVec::iterator I = Attrs.begin(); I != E; ++I) {
|
||||
APValue Result;
|
||||
EnableIfAttr *EIA = cast<EnableIfAttr>(*I);
|
||||
if (EIA->getCond()->isValueDependent()) {
|
||||
// Don't even try now, we'll examine it after instantiation.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!EIA->getCond()->EvaluateWithSubstitution(
|
||||
Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)) ||
|
||||
!Result.isInt() || !Result.getInt().getBoolValue()) {
|
||||
Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) {
|
||||
if (!ContainsValueDependentExpr)
|
||||
return EIA;
|
||||
} else if (!Result.isInt() || !Result.getInt().getBoolValue()) {
|
||||
return EIA;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,3 +77,44 @@ void test() {
|
|||
typedep(1);
|
||||
typedep(n); // expected-note{{in instantiation of function template specialization 'typedep<Nothing>' requested here}}
|
||||
}
|
||||
|
||||
template <typename T> class C {
|
||||
void f() __attribute__((enable_if(T::expr == 0, ""))) {}
|
||||
void g() { f(); }
|
||||
};
|
||||
|
||||
int fn3(bool b) __attribute__((enable_if(b, "")));
|
||||
template <class T> void test3() {
|
||||
fn3(sizeof(T) == 1);
|
||||
}
|
||||
|
||||
// FIXME: issue an error (without instantiation) because ::h(T()) is not
|
||||
// convertible to bool, because return types aren't overloadable.
|
||||
void h(int);
|
||||
template <typename T> void outer() {
|
||||
void local_function() __attribute__((enable_if(::h(T()), "")));
|
||||
local_function();
|
||||
};
|
||||
|
||||
namespace PR20988 {
|
||||
struct Integer {
|
||||
Integer(int);
|
||||
};
|
||||
|
||||
int fn1(const Integer &) __attribute__((enable_if(true, "")));
|
||||
template <class T> void test1() {
|
||||
int &expr = T::expr();
|
||||
fn1(expr);
|
||||
}
|
||||
|
||||
int fn2(const Integer &) __attribute__((enable_if(false, ""))); // expected-note{{candidate disabled}}
|
||||
template <class T> void test2() {
|
||||
int &expr = T::expr();
|
||||
fn2(expr); // expected-error{{no matching function for call to 'fn2'}}
|
||||
}
|
||||
|
||||
int fn3(bool b) __attribute__((enable_if(b, "")));
|
||||
template <class T> void test3() {
|
||||
fn3(sizeof(T) == 1);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue