Refactor ActOnDeclarationNameExpr into a "parsing action" part and a
"semantic analysis" part. Use the "semantic analysis" part when performing template instantiation on a DeclRefExpr, rather than an ad hoc list of rules to construct DeclRefExprs from the instantiation. A test case for this change will come in with a large commit, which illustrates what I was actually trying to work on. llvm-svn: 74528
This commit is contained in:
parent
16f652876f
commit
3256d04d22
|
@ -1401,7 +1401,11 @@ public:
|
|||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS,
|
||||
bool isAddressOfOperand = false);
|
||||
|
||||
OwningExprResult BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS,
|
||||
bool isAddressOfOperand);
|
||||
|
||||
virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
|
||||
tok::TokenKind Kind);
|
||||
virtual OwningExprResult ActOnNumericConstant(const Token &);
|
||||
|
|
|
@ -970,7 +970,64 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
return ExprError(Diag(Loc, diag::err_undeclared_var_use) << Name);
|
||||
}
|
||||
}
|
||||
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
|
||||
// Warn about constructs like:
|
||||
// if (void *X = foo()) { ... } else { X }.
|
||||
// In the else block, the pointer is always false.
|
||||
|
||||
// FIXME: In a template instantiation, we don't have scope
|
||||
// information to check this property.
|
||||
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
|
||||
Scope *CheckS = S;
|
||||
while (CheckS) {
|
||||
if (CheckS->isWithinElse() &&
|
||||
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
|
||||
if (Var->getType()->isBooleanType())
|
||||
ExprError(Diag(Loc, diag::warn_value_always_false)
|
||||
<< Var->getDeclName());
|
||||
else
|
||||
ExprError(Diag(Loc, diag::warn_value_always_zero)
|
||||
<< Var->getDeclName());
|
||||
break;
|
||||
}
|
||||
|
||||
// Move up one more control parent to check again.
|
||||
CheckS = CheckS->getControlParent();
|
||||
if (CheckS)
|
||||
CheckS = CheckS->getParent();
|
||||
}
|
||||
}
|
||||
} else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) {
|
||||
if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
|
||||
// C99 DR 316 says that, if a function type comes from a
|
||||
// function definition (without a prototype), that type is only
|
||||
// used for checking compatibility. Therefore, when referencing
|
||||
// the function, we pretend that we don't have the full function
|
||||
// type.
|
||||
if (DiagnoseUseOfDecl(Func, Loc))
|
||||
return ExprError();
|
||||
|
||||
QualType T = Func->getType();
|
||||
QualType NoProtoType = T;
|
||||
if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
|
||||
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
|
||||
return BuildDeclRefExpr(Func, NoProtoType, Loc, false, false, SS);
|
||||
}
|
||||
}
|
||||
|
||||
return BuildDeclarationNameExpr(Loc, D, HasTrailingLParen, SS, isAddressOfOperand);
|
||||
}
|
||||
|
||||
/// \brief Complete semantic analysis for a reference to the given declaration.
|
||||
Sema::OwningExprResult
|
||||
Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
|
||||
bool HasTrailingLParen,
|
||||
const CXXScopeSpec *SS,
|
||||
bool isAddressOfOperand) {
|
||||
assert(D && "Cannot refer to a NULL declaration");
|
||||
DeclarationName Name = D->getDeclName();
|
||||
|
||||
// If this is an expression of the form &Class::member, don't build an
|
||||
// implicit member ref, because we want a pointer to the member in general,
|
||||
// not any specific instance's member.
|
||||
|
@ -1094,51 +1151,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
// this check when we're going to perform argument-dependent lookup
|
||||
// on this function name, because this might not be the function
|
||||
// that overload resolution actually selects.
|
||||
bool ADL = getLangOptions().CPlusPlus && (!SS || !SS->isSet()) &&
|
||||
HasTrailingLParen;
|
||||
if (!(ADL && isa<FunctionDecl>(VD)) && DiagnoseUseOfDecl(VD, Loc))
|
||||
return ExprError();
|
||||
|
||||
if (VarDecl *Var = dyn_cast<VarDecl>(VD)) {
|
||||
// Warn about constructs like:
|
||||
// if (void *X = foo()) { ... } else { X }.
|
||||
// In the else block, the pointer is always false.
|
||||
|
||||
// FIXME: In a template instantiation, we don't have scope
|
||||
// information to check this property.
|
||||
if (Var->isDeclaredInCondition() && Var->getType()->isScalarType()) {
|
||||
Scope *CheckS = S;
|
||||
while (CheckS) {
|
||||
if (CheckS->isWithinElse() &&
|
||||
CheckS->getControlParent()->isDeclScope(DeclPtrTy::make(Var))) {
|
||||
if (Var->getType()->isBooleanType())
|
||||
ExprError(Diag(Loc, diag::warn_value_always_false)
|
||||
<< Var->getDeclName());
|
||||
else
|
||||
ExprError(Diag(Loc, diag::warn_value_always_zero)
|
||||
<< Var->getDeclName());
|
||||
break;
|
||||
}
|
||||
|
||||
// Move up one more control parent to check again.
|
||||
CheckS = CheckS->getControlParent();
|
||||
if (CheckS)
|
||||
CheckS = CheckS->getParent();
|
||||
}
|
||||
}
|
||||
} else if (FunctionDecl *Func = dyn_cast<FunctionDecl>(VD)) {
|
||||
if (!getLangOptions().CPlusPlus && !Func->hasPrototype()) {
|
||||
// C99 DR 316 says that, if a function type comes from a
|
||||
// function definition (without a prototype), that type is only
|
||||
// used for checking compatibility. Therefore, when referencing
|
||||
// the function, we pretend that we don't have the full function
|
||||
// type.
|
||||
QualType T = Func->getType();
|
||||
QualType NoProtoType = T;
|
||||
if (const FunctionProtoType *Proto = T->getAsFunctionProtoType())
|
||||
NoProtoType = Context.getFunctionNoProtoType(Proto->getResultType());
|
||||
return BuildDeclRefExpr(VD, NoProtoType, Loc, false, false, SS);
|
||||
}
|
||||
}
|
||||
|
||||
// Only create DeclRefExpr's for valid Decl's.
|
||||
if (VD->isInvalidDecl())
|
||||
return ExprError();
|
||||
|
|
|
@ -865,6 +865,6 @@ void Sema::PerformPendingImplicitInstantiations() {
|
|||
if (!Function->getBody())
|
||||
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function);
|
||||
|
||||
// FIXME: instantiation static member variables
|
||||
// FIXME: instantiate static member variables
|
||||
}
|
||||
}
|
||||
|
|
|
@ -156,18 +156,15 @@ TemplateExprInstantiator::VisitDeclRefExpr(DeclRefExpr *E) {
|
|||
false, false));
|
||||
}
|
||||
|
||||
ValueDecl *NewD
|
||||
= dyn_cast_or_null<ValueDecl>(SemaRef.InstantiateCurrentDeclRef(D));
|
||||
if (!NewD)
|
||||
NamedDecl *InstD = SemaRef.InstantiateCurrentDeclRef(D);
|
||||
if (!InstD)
|
||||
return SemaRef.ExprError();
|
||||
|
||||
// FIXME: Build QualifiedDeclRefExpr?
|
||||
QualType T = NewD->getType();
|
||||
return SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(NewD,
|
||||
T.getNonReferenceType(),
|
||||
E->getLocation(),
|
||||
T->isDependentType(),
|
||||
T->isDependentType()));
|
||||
// FIXME: nested-name-specifier for QualifiedDeclRefExpr
|
||||
return SemaRef.BuildDeclarationNameExpr(E->getLocation(), InstD,
|
||||
/*FIXME:*/false,
|
||||
/*FIXME:*/0,
|
||||
/*FIXME:*/false);
|
||||
}
|
||||
|
||||
Sema::OwningExprResult
|
||||
|
|
Loading…
Reference in New Issue