Skip to content

Commit

Permalink
Fix a crash bug when comparing overload quality of conversion operato…
Browse files Browse the repository at this point in the history
…rs with conversion constructors.

Remove an atrocious amount of trailing whitespace in the overloaded operator mangler. Sorry, couldn't help myself.
Change the DeclType parameter of Sema::CheckReferenceInit to be passed by value instead of reference. It wasn't changed anywhere.
Let the parser handle C++'s irregular grammar around assignment-expression and conditional-expression.
And finally, the reason for all this stuff: implement C++ semantics for the conditional operator. The implementation is complete except for determining lvalueness.

llvm-svn: 69299
  • Loading branch information
Sebastian Redl committed Apr 16, 2009
1 parent 8d25b09 commit 1a99f44
Show file tree
Hide file tree
Showing 12 changed files with 587 additions and 80 deletions.
10 changes: 9 additions & 1 deletion clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1123,11 +1123,19 @@ def err_bad_memptr_rhs : Error<
"right hand operand to %0 has non pointer-to-member type %1">;
def err_memptr_rhs_incomplete : Error<
"right hand operand is a pointer to member of incomplete type %0">;

def err_bad_memptr_lhs : Error<
"left hand operand to %0 must be a %select{|pointer to }1class "
"compatible with the right hand operand, but is %2">;

def err_conditional_void_nonvoid : Error<
"%select{left|right}1 operand to ? is void, but %select{right|left}1 operand "
"is of type %0">;
def err_conditional_ambiguous : Error<
"conditional expression is ambiguous; %0 can be converted to %1 "
"and vice versa">;
def err_conditional_ambiguous_ovl : Error<
"conditional expression is ambiguous; %0 and %1 can be converted to several "
"common types">;

def err_invalid_use_of_function_type : Error<
"a function type is not allowed here">;
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/OperatorKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ OVERLOADED_OPERATOR(ArrowStar , "->*" , arrowstar , false, t
OVERLOADED_OPERATOR(Arrow , "->" , arrow , true , false, true)
OVERLOADED_OPERATOR_MULTI(Call , "()" , true , true , true)
OVERLOADED_OPERATOR_MULTI(Subscript , "[]" , false, true , true)
// ?: can *not* be overloaded, but we need the overload
// resolution machinery for it.
OVERLOADED_OPERATOR_MULTI(Conditional , "?" , false, true , false)

#undef OVERLOADED_OPERATOR_MULTI
#undef OVERLOADED_OPERATOR
111 changes: 56 additions & 55 deletions clang/lib/CodeGen/Mangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,97 +283,98 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC) {
void
CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) {
switch (OO) {
// <operator-name> ::= nw # new
// <operator-name> ::= nw # new
case OO_New: Out << "nw"; break;
// ::= na # new[]
case OO_Array_New: Out << "na"; break;
// ::= dl # delete
// ::= dl # delete
case OO_Delete: Out << "dl"; break;
// ::= da # delete[]
// ::= da # delete[]
case OO_Array_Delete: Out << "da"; break;
// ::= ps # + (unary)
// ::= pl # +
case OO_Plus: Out << (Arity == 1? "ps" : "pl"); break;
// ::= ng # - (unary)
// ::= mi # -
// ::= ng # - (unary)
// ::= mi # -
case OO_Minus: Out << (Arity == 1? "ng" : "mi"); break;
// ::= ad # & (unary)
// ::= an # &
// ::= ad # & (unary)
// ::= an # &
case OO_Amp: Out << (Arity == 1? "ad" : "an"); break;
// ::= de # * (unary)
// ::= ml # *
// ::= de # * (unary)
// ::= ml # *
case OO_Star: Out << (Arity == 1? "de" : "ml"); break;
// ::= co # ~
// ::= co # ~
case OO_Tilde: Out << "co"; break;
// ::= dv # /
// ::= dv # /
case OO_Slash: Out << "dv"; break;
// ::= rm # %
// ::= rm # %
case OO_Percent: Out << "rm"; break;
// ::= or # |
case OO_Pipe: Out << "or"; break;
// ::= eo # ^
// ::= or # |
case OO_Pipe: Out << "or"; break;
// ::= eo # ^
case OO_Caret: Out << "eo"; break;
// ::= aS # =
// ::= aS # =
case OO_Equal: Out << "aS"; break;
// ::= pL # +=
// ::= pL # +=
case OO_PlusEqual: Out << "pL"; break;
// ::= mI # -=
// ::= mI # -=
case OO_MinusEqual: Out << "mI"; break;
// ::= mL # *=
// ::= mL # *=
case OO_StarEqual: Out << "mL"; break;
// ::= dV # /=
// ::= dV # /=
case OO_SlashEqual: Out << "dV"; break;
// ::= rM # %=
case OO_PercentEqual: Out << "rM"; break;
// ::= aN # &=
case OO_AmpEqual: Out << "aN"; break;
// ::= oR # |=
case OO_PipeEqual: Out << "oR"; break;
// ::= eO # ^=
case OO_CaretEqual: Out << "eO"; break;
// ::= ls # <<
// ::= rM # %=
case OO_PercentEqual: Out << "rM"; break;
// ::= aN # &=
case OO_AmpEqual: Out << "aN"; break;
// ::= oR # |=
case OO_PipeEqual: Out << "oR"; break;
// ::= eO # ^=
case OO_CaretEqual: Out << "eO"; break;
// ::= ls # <<
case OO_LessLess: Out << "ls"; break;
// ::= rs # >>
case OO_GreaterGreater: Out << "rs"; break;
// ::= lS # <<=
case OO_LessLessEqual: Out << "lS"; break;
// ::= rS # >>=
case OO_GreaterGreaterEqual: Out << "rS"; break;
// ::= rs # >>
case OO_GreaterGreater: Out << "rs"; break;
// ::= lS # <<=
case OO_LessLessEqual: Out << "lS"; break;
// ::= rS # >>=
case OO_GreaterGreaterEqual: Out << "rS"; break;
// ::= eq # ==
case OO_EqualEqual: Out << "eq"; break;
// ::= ne # !=
case OO_ExclaimEqual: Out << "ne"; break;
// ::= lt # <
// ::= ne # !=
case OO_ExclaimEqual: Out << "ne"; break;
// ::= lt # <
case OO_Less: Out << "lt"; break;
// ::= gt # >
// ::= gt # >
case OO_Greater: Out << "gt"; break;
// ::= le # <=
// ::= le # <=
case OO_LessEqual: Out << "le"; break;
// ::= ge # >=
// ::= ge # >=
case OO_GreaterEqual: Out << "ge"; break;
// ::= nt # !
// ::= nt # !
case OO_Exclaim: Out << "nt"; break;
// ::= aa # &&
// ::= aa # &&
case OO_AmpAmp: Out << "aa"; break;
// ::= oo # ||
case OO_PipePipe: Out << "oo"; break;
// ::= pp # ++
case OO_PlusPlus: Out << "pp"; break;
// ::= mm # --
// ::= oo # ||
case OO_PipePipe: Out << "oo"; break;
// ::= pp # ++
case OO_PlusPlus: Out << "pp"; break;
// ::= mm # --
case OO_MinusMinus: Out << "mm"; break;
// ::= cm # ,
case OO_Comma: Out << "cm"; break;
// ::= pm # ->*
// ::= cm # ,
case OO_Comma: Out << "cm"; break;
// ::= pm # ->*
case OO_ArrowStar: Out << "pm"; break;
// ::= pt # ->
// ::= pt # ->
case OO_Arrow: Out << "pt"; break;
// ::= cl # ()
// ::= cl # ()
case OO_Call: Out << "cl"; break;
// ::= ix # []
// ::= ix # []
case OO_Subscript: Out << "ix"; break;
// UNSUPPORTED: ::= qu # ?

case OO_None:
case OO_None:
case OO_Conditional:
case NUM_OVERLOADED_OPERATORS:
assert(false && "Not an overloaded operator");
break;
Expand Down
13 changes: 12 additions & 1 deletion clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
/// logical-OR-expression
/// logical-OR-expression '?' expression ':' conditional-expression
/// [GNU] logical-OR-expression '?' ':' conditional-expression
/// [C++] the third operand is an assignment-expression
///
/// assignment-expression: [C99 6.5.16]
/// conditional-expression
Expand Down Expand Up @@ -332,7 +333,17 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
}

// Parse another leaf here for the RHS of the operator.
OwningExprResult RHS(ParseCastExpression(false));
// ParseCastExpression works here because all RHS expressions in C have it
// as a prefix, at least. However, in C++, an assignment-expression could
// be a throw-expression, which is not a valid cast-expression.
// Therefore we need some special-casing here.
// Also note that the third operand of the conditional operator is
// an assignment-expression in C++.
OwningExprResult RHS(Actions);
if (getLang().CPlusPlus && NextTokPrec <= prec::Conditional)
RHS = ParseAssignmentExpression();
else
RHS = ParseCastExpression(false);
if (RHS.isInvalid())
return move(RHS);

Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2382,6 +2382,8 @@ class Sema : public Action {
Expr *lex, Expr *&rex, SourceLocation OpLoc);
QualType CheckConditionalOperands( // C99 6.5.15
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
QualType CXXCheckConditionalOperands( // C++ 5.16
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);

/// type checking for vector binary operators.
inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);
Expand Down Expand Up @@ -2435,7 +2437,7 @@ class Sema : public Action {
ReferenceCompareResult CompareReferenceRelationship(QualType T1, QualType T2,
bool& DerivedToBase);

bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType &declType,
bool CheckReferenceInit(Expr *&simpleInit_or_initList, QualType declType,
ImplicitConversionSequence *ICS = 0,
bool SuppressUserConversions = false,
bool AllowExplicit = false,
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2018,7 +2018,7 @@ Sema::CompareReferenceRelationship(QualType T1, QualType T2,
/// conversion functions.
/// When @p ForceRValue, we unconditionally treat the initializer as an rvalue.
bool
Sema::CheckReferenceInit(Expr *&Init, QualType &DeclType,
Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
ImplicitConversionSequence *ICS,
bool SuppressUserConversions,
bool AllowExplicit, bool ForceRValue) {
Expand Down
16 changes: 8 additions & 8 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2588,6 +2588,10 @@ Sema::ActOnCastExpr(SourceLocation LParenLoc, TypeTy *Ty,
/// C99 6.5.15
QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
SourceLocation QuestionLoc) {
// C++ is sufficiently different to merit its own checker.
if (getLangOptions().CPlusPlus)
return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);

UsualUnaryConversions(Cond);
UsualUnaryConversions(LHS);
UsualUnaryConversions(RHS);
Expand All @@ -2596,17 +2600,13 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
QualType RHSTy = RHS->getType();

// first, check the condition.
if (!Cond->isTypeDependent()) {
if (!CondTy->isScalarType()) { // C99 6.5.15p2
Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return QualType();
}
if (!CondTy->isScalarType()) { // C99 6.5.15p2
Diag(Cond->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return QualType();
}

// Now check the two expressions.
if ((LHS && LHS->isTypeDependent()) || (RHS && RHS->isTypeDependent()))
return Context.DependentTy;

// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
Expand Down

0 comments on commit 1a99f44

Please sign in to comment.