[CUDA] Warn undeclared identifiers in CUDA kernel calls

Value, type, and instantiation dependence were not being handled
correctly for CUDAKernelCallExpr AST nodes. As a result, if an
undeclared identifier was used in the triple-angle-bracket kernel call
configuration, there would be no error during parsing, and there would
be a crash during code gen. This patch makes sure that an error will be
issued during parsing in this case, just as there would be for any other
use of an undeclared identifier in C++.

Patch by Jason Henline.

Reviewers: jlebar, rsmith

Differential Revision: http://reviews.llvm.org/D15858

llvm-svn: 257839
This commit is contained in:
Justin Lebar 2016-01-14 23:31:30 +00:00
parent ac1e2f8f03
commit f8bdacbadc
5 changed files with 68 additions and 31 deletions

View File

@ -2137,11 +2137,15 @@ class CallExpr : public Expr {
unsigned NumArgs;
SourceLocation RParenLoc;
void updateDependenciesFromArg(Expr *Arg);
protected:
// These versions of the constructor are for derived classes.
CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc);
CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
ExprValueKind VK, SourceLocation rparenloc);
CallExpr(const ASTContext &C, StmtClass SC, Expr *fn, ArrayRef<Expr *> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc);
CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty);

View File

@ -66,8 +66,7 @@ public:
CXXOperatorCallExpr(ASTContext& C, OverloadedOperatorKind Op, Expr *fn,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation operatorloc, bool fpContractable)
: CallExpr(C, CXXOperatorCallExprClass, fn, 0, args, t, VK,
operatorloc),
: CallExpr(C, CXXOperatorCallExprClass, fn, args, t, VK, operatorloc),
Operator(Op), FPContractable(fpContractable) {
Range = getSourceRangeImpl();
}
@ -125,7 +124,7 @@ class CXXMemberCallExpr : public CallExpr {
public:
CXXMemberCallExpr(ASTContext &C, Expr *fn, ArrayRef<Expr*> args,
QualType t, ExprValueKind VK, SourceLocation RP)
: CallExpr(C, CXXMemberCallExprClass, fn, 0, args, t, VK, RP) {}
: CallExpr(C, CXXMemberCallExprClass, fn, args, t, VK, RP) {}
CXXMemberCallExpr(ASTContext &C, EmptyShell Empty)
: CallExpr(C, CXXMemberCallExprClass, Empty) { }
@ -160,9 +159,7 @@ public:
CUDAKernelCallExpr(ASTContext &C, Expr *fn, CallExpr *Config,
ArrayRef<Expr*> args, QualType t, ExprValueKind VK,
SourceLocation RP)
: CallExpr(C, CUDAKernelCallExprClass, fn, END_PREARG, args, t, VK, RP) {
setConfig(Config);
}
: CallExpr(C, CUDAKernelCallExprClass, fn, Config, args, t, VK, RP) {}
CUDAKernelCallExpr(ASTContext &C, EmptyShell Empty)
: CallExpr(C, CUDAKernelCallExprClass, END_PREARG, Empty) { }
@ -171,7 +168,20 @@ public:
return cast_or_null<CallExpr>(getPreArg(CONFIG));
}
CallExpr *getConfig() { return cast_or_null<CallExpr>(getPreArg(CONFIG)); }
void setConfig(CallExpr *E) { setPreArg(CONFIG, E); }
/// \brief Sets the kernel configuration expression.
///
/// Note that this method cannot be called if config has already been set to a
/// non-null value.
void setConfig(CallExpr *E) {
assert(!getConfig() &&
"Cannot call setConfig if config is not null");
setPreArg(CONFIG, E);
setInstantiationDependent(isInstantiationDependent() ||
E->isInstantiationDependent());
setContainsUnexpandedParameterPack(containsUnexpandedParameterPack() ||
E->containsUnexpandedParameterPack());
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == CUDAKernelCallExprClass;
@ -398,7 +408,7 @@ public:
UserDefinedLiteral(const ASTContext &C, Expr *Fn, ArrayRef<Expr*> Args,
QualType T, ExprValueKind VK, SourceLocation LitEndLoc,
SourceLocation SuffixLoc)
: CallExpr(C, UserDefinedLiteralClass, Fn, 0, Args, T, VK, LitEndLoc),
: CallExpr(C, UserDefinedLiteralClass, Fn, Args, T, VK, LitEndLoc),
UDSuffixLoc(SuffixLoc) {}
explicit UserDefinedLiteral(const ASTContext &C, EmptyShell Empty)
: CallExpr(C, UserDefinedLiteralClass, Empty) {}

View File

@ -1138,28 +1138,23 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) {
// Postfix Operators.
//===----------------------------------------------------------------------===//
CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn,
unsigned NumPreArgs, ArrayRef<Expr*> args, QualType t,
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
ArrayRef<Expr *> preargs, ArrayRef<Expr *> args, QualType t,
ExprValueKind VK, SourceLocation rparenloc)
: Expr(SC, t, VK, OK_Ordinary,
fn->isTypeDependent(),
fn->isValueDependent(),
fn->isInstantiationDependent(),
fn->containsUnexpandedParameterPack()),
NumArgs(args.size()) {
: Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(),
fn->isValueDependent(), fn->isInstantiationDependent(),
fn->containsUnexpandedParameterPack()),
NumArgs(args.size()) {
SubExprs = new (C) Stmt*[args.size()+PREARGS_START+NumPreArgs];
unsigned NumPreArgs = preargs.size();
SubExprs = new (C) Stmt *[args.size()+PREARGS_START+NumPreArgs];
SubExprs[FN] = fn;
for (unsigned i = 0; i != NumPreArgs; ++i) {
updateDependenciesFromArg(preargs[i]);
SubExprs[i+PREARGS_START] = preargs[i];
}
for (unsigned i = 0; i != args.size(); ++i) {
if (args[i]->isTypeDependent())
ExprBits.TypeDependent = true;
if (args[i]->isValueDependent())
ExprBits.ValueDependent = true;
if (args[i]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (args[i]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
updateDependenciesFromArg(args[i]);
SubExprs[i+PREARGS_START+NumPreArgs] = args[i];
}
@ -1167,9 +1162,14 @@ CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn,
RParenLoc = rparenloc;
}
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, Expr *fn,
ArrayRef<Expr *> args, QualType t, ExprValueKind VK,
SourceLocation rparenloc)
: CallExpr(C, SC, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc) {}
CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args,
QualType t, ExprValueKind VK, SourceLocation rparenloc)
: CallExpr(C, CallExprClass, fn, /*NumPreArgs=*/0, args, t, VK, rparenloc) {
: CallExpr(C, CallExprClass, fn, ArrayRef<Expr *>(), args, t, VK, rparenloc) {
}
CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty)
@ -1179,10 +1179,21 @@ CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs,
EmptyShell Empty)
: Expr(SC, Empty), SubExprs(nullptr), NumArgs(0) {
// FIXME: Why do we allocate this?
SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs];
SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs]();
CallExprBits.NumPreArgs = NumPreArgs;
}
void CallExpr::updateDependenciesFromArg(Expr *Arg) {
if (Arg->isTypeDependent())
ExprBits.TypeDependent = true;
if (Arg->isValueDependent())
ExprBits.ValueDependent = true;
if (Arg->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (Arg->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
}
Decl *CallExpr::getCalleeDecl() {
Expr *CEE = getCallee()->IgnoreParenImpCasts();

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
#include "Inputs/cuda.h"
__global__ void k1() {}
template<int ...Dimensions> void k1Wrapper() {
void (*f)() = [] { k1<<<Dimensions, Dimensions>>>(); }; // expected-error {{initializer contains unexpanded parameter pack 'Dimensions'}}
void (*g[])() = { [] { k1<<<Dimensions, Dimensions>>>(); } ... }; // ok
}

View File

@ -23,4 +23,6 @@ int main(void) {
int (*fp)(int) = h2;
fp<<<1, 1>>>(42); // expected-error {{must have void return type}}
g1<<<undeclared, 1>>>(42); // expected-error {{use of undeclared identifier 'undeclared'}}
}