C1X: implement generic selections

As an extension, generic selection support has been added for all
supported languages.  The syntax is the same as for C1X.

llvm-svn: 129554
This commit is contained in:
Peter Collingbourne 2011-04-15 00:35:48 +00:00
parent a686b5f8bf
commit 9114759641
40 changed files with 845 additions and 57 deletions

View File

@ -52,6 +52,7 @@ td {
<li><a href="#checking_type_traits">Checks for Type Traits</a></li>
<li><a href="#blocks">Blocks</a></li>
<li><a href="#overloading-in-c">Function Overloading in C</a></li>
<li><a href="#generic-selections">Generic Selections</a></li>
<li><a href="#builtins">Builtin Functions</a>
<ul>
<li><a href="#__builtin_shufflevector">__builtin_shufflevector</a></li>
@ -603,6 +604,20 @@ caveats to this use of name mangling:</p>
<p>Query for this feature with __has_feature(attribute_overloadable).</p>
<!-- ======================================================================= -->
<h2 id="generic-selections">Generic Selections</h2>
<!-- ======================================================================= -->
<p>The C1X generic selection expression is available in all languages
supported by Clang. The syntax is the same as that given in the C1X draft
standard.</p>
<p>In C, type compatibility is decided according to the rules given in the
appropriate standard, but in C++, which lacks the type compatibility rules
used in C, types are considered compatible only if they are equivalent.</p>
<p>Query for this feature with __has_feature(generic_selections).</p>
<!-- ======================================================================= -->
<h2 id="builtins">Builtin Functions</h2>
<!-- ======================================================================= -->

View File

@ -3679,6 +3679,118 @@ public:
};
/// \brief Represents a C1X generic selection.
///
/// A generic selection (C1X 6.5.1.1) contains an unevaluated controlling
/// expression, followed by one or more generic associations. Each generic
/// association specifies a type name and an expression, or "default" and an
/// expression (in which case it is known as a default generic association).
/// The type and value of the generic selection are identical to those of its
/// result expression, which is defined as the expression in the generic
/// association with a type name that is compatible with the type of the
/// controlling expression, or the expression in the default generic association
/// if no types are compatible. For example:
///
/// @code
/// _Generic(X, double: 1, float: 2, default: 3)
/// @endcode
///
/// The above expression evaluates to 1 if 1.0 is substituted for X, 2 if 1.0f
/// or 3 if "hello".
///
/// As an extension, generic selections are allowed in C++, where the following
/// additional semantics apply:
///
/// Any generic selection whose controlling expression is type-dependent or
/// which names a dependent type in its association list is result-dependent,
/// which means that the choice of result expression is dependent.
/// Result-dependent generic associations are both type- and value-dependent.
class GenericSelectionExpr : public Expr {
enum { CONTROLLING, END_EXPR };
TypeSourceInfo **AssocTypes;
Stmt **SubExprs;
unsigned NumAssocs, ResultIndex;
SourceLocation GenericLoc, DefaultLoc, RParenLoc;
public:
GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
unsigned NumAssocs, SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack,
unsigned ResultIndex);
/// This constructor is used in the result-dependent case.
GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
unsigned NumAssocs, SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack);
explicit GenericSelectionExpr(EmptyShell Empty)
: Expr(GenericSelectionExprClass, Empty) { }
unsigned getNumAssocs() const { return NumAssocs; }
SourceLocation getGenericLoc() const { return GenericLoc; }
SourceLocation getDefaultLoc() const { return DefaultLoc; }
SourceLocation getRParenLoc() const { return RParenLoc; }
const Expr *getAssocExpr(unsigned i) const {
return cast<Expr>(SubExprs[END_EXPR+i]);
}
Expr *getAssocExpr(unsigned i) { return cast<Expr>(SubExprs[END_EXPR+i]); }
const TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) const {
return AssocTypes[i];
}
TypeSourceInfo *getAssocTypeSourceInfo(unsigned i) { return AssocTypes[i]; }
QualType getAssocType(unsigned i) const {
if (const TypeSourceInfo *TS = getAssocTypeSourceInfo(i))
return TS->getType();
else
return QualType();
}
const Expr *getControllingExpr() const {
return cast<Expr>(SubExprs[CONTROLLING]);
}
Expr *getControllingExpr() { return cast<Expr>(SubExprs[CONTROLLING]); }
/// Whether this generic selection is result-dependent.
bool isResultDependent() const { return ResultIndex == -1U; }
/// The zero-based index of the result expression's generic association in
/// the generic selection's association list. Defined only if the
/// generic selection is not result-dependent.
unsigned getResultIndex() const {
assert(!isResultDependent() && "Generic selection is result-dependent");
return ResultIndex;
}
/// The generic selection's result expression. Defined only if the
/// generic selection is not result-dependent.
const Expr *getResultExpr() const { return getAssocExpr(getResultIndex()); }
Expr *getResultExpr() { return getAssocExpr(getResultIndex()); }
SourceRange getSourceRange() const {
return SourceRange(GenericLoc, RParenLoc);
}
static bool classof(const Stmt *T) {
return T->getStmtClass() == GenericSelectionExprClass;
}
static bool classof(const GenericSelectionExpr *) { return true; }
child_range children() {
return child_range(SubExprs, SubExprs+END_EXPR+NumAssocs);
}
friend class ASTStmtReader;
};
//===----------------------------------------------------------------------===//
// Clang Extensions
//===----------------------------------------------------------------------===//

View File

@ -1777,6 +1777,22 @@ bool RecursiveASTVisitor<Derived>::TraverseInitListExpr(InitListExpr *S) {
return true;
}
// GenericSelectionExpr is a special case because the types and expressions
// are interleaved. We also need to watch out for null types (default
// generic associations).
template<typename Derived>
bool RecursiveASTVisitor<Derived>::
TraverseGenericSelectionExpr(GenericSelectionExpr *S) {
TRY_TO(WalkUpFromGenericSelectionExpr(S));
TRY_TO(TraverseStmt(S->getControllingExpr()));
for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
if (TypeSourceInfo *TS = S->getAssocTypeSourceInfo(i))
TRY_TO(TraverseTypeLoc(TS->getTypeLoc()));
TRY_TO(TraverseStmt(S->getAssocExpr(i)));
}
return true;
}
DEF_TRAVERSE_STMT(CXXScalarValueInitExpr, {
// This is called for code like 'return T()' where T is a built-in
// (i.e. non-class) type.

View File

@ -67,6 +67,13 @@ def ext_ms_enum_fixed_underlying_type : Extension<
"enumeration types with a fixed underlying type are a Microsoft extension">,
InGroup<Microsoft>;
def ext_c1x_generic_selection : Extension<
"generic selections are a C1X-specific feature">;
def err_duplicate_default_assoc : Error<
"duplicate default generic association">;
def note_previous_default_assoc : Note<
"previous default generic association is here">;
def ext_gnu_indirect_goto : Extension<
"use of GNU indirect-goto extension">, InGroup<GNU>;
def ext_gnu_address_of_label : Extension<

View File

@ -3646,6 +3646,21 @@ def warn_stringcompare : Warning<
"result of comparison against %select{a string literal|@encode}0 is "
"unspecified (use strncmp instead)">;
// Generic selections.
def err_assoc_type_incomplete : Error<
"type %0 in generic association incomplete">;
def err_assoc_type_nonobject : Error<
"type %0 in generic association not an object type">;
def err_assoc_type_variably_modified : Error<
"type %0 in generic association is a variably modified type">;
def err_assoc_compatible_types : Error<
"type %0 in generic association compatible with previously specified type %1">;
def note_compat_assoc : Note<
"compatible type %0 specified here">;
def err_generic_sel_no_match : Error<
"controlling expression type %0 not compatible with any generic association type">;
def err_generic_sel_multi_match : Error<
"controlling expression type %0 compatible with %1 generic association types">;
// Blocks

View File

@ -75,6 +75,7 @@ def DesignatedInitExpr : DStmt<Expr>;
def ImplicitValueInitExpr : DStmt<Expr>;
def ParenListExpr : DStmt<Expr>;
def VAArgExpr : DStmt<Expr>;
def GenericSelectionExpr : DStmt<Expr>;
// GNU Extensions.
def AddrLabelExpr : DStmt<Expr>;

View File

@ -238,6 +238,7 @@ KEYWORD(volatile , KEYALL)
KEYWORD(while , KEYALL)
KEYWORD(_Bool , KEYNOCXX)
KEYWORD(_Complex , KEYALL)
KEYWORD(_Generic , KEYALL)
KEYWORD(_Imaginary , KEYALL)
KEYWORD(__func__ , KEYALL)

View File

@ -1101,6 +1101,8 @@ private:
ExprResult ParseStringLiteralExpression();
ExprResult ParseGenericSelectionExpression();
//===--------------------------------------------------------------------===//
// C++ Expressions
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);

View File

@ -383,11 +383,18 @@ namespace clang {
template<typename T> T **takeAs() { return reinterpret_cast<T**>(take()); }
};
/// An opaque type for threading parsed type information through the
/// parser.
typedef OpaquePtr<QualType> ParsedType;
typedef UnionOpaquePtr<QualType> UnionParsedType;
/// A SmallVector of statements, with stack size 32 (as that is the only one
/// used.)
typedef ASTOwningVector<Stmt*, 32> StmtVector;
/// A SmallVector of expressions, with stack size 12 (the maximum used.)
typedef ASTOwningVector<Expr*, 12> ExprVector;
/// A SmallVector of types.
typedef ASTOwningVector<ParsedType, 12> TypeVector;
template <class T, unsigned N> inline
ASTMultiPtr<T> move_arg(ASTOwningVector<T, N> &vec) {
@ -421,11 +428,6 @@ namespace clang {
static const bool value = true;
};
/// An opaque type for threading parsed type information through the
/// parser.
typedef OpaquePtr<QualType> ParsedType;
typedef UnionOpaquePtr<QualType> UnionParsedType;
typedef ActionResult<Expr*> ExprResult;
typedef ActionResult<Stmt*> StmtResult;
typedef ActionResult<ParsedType> TypeResult;
@ -440,6 +442,7 @@ namespace clang {
typedef ASTMultiPtr<Expr*> MultiExprArg;
typedef ASTMultiPtr<Stmt*> MultiStmtArg;
typedef ASTMultiPtr<ParsedType> MultiTypeArg;
typedef ASTMultiPtr<TemplateParameterList*> MultiTemplateParamsArg;
inline ExprResult ExprError() { return ExprResult(true); }

View File

@ -2009,6 +2009,20 @@ public:
/// fragments (e.g. "foo" "bar" L"baz").
ExprResult ActOnStringLiteral(const Token *Toks, unsigned NumToks);
ExprResult ActOnGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
MultiTypeArg Types,
MultiExprArg Exprs);
ExprResult CreateGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
TypeSourceInfo **Types,
Expr **Exprs,
unsigned NumAssocs);
// Binary/Unary Operators. 'Tok' is the token for the operator.
ExprResult CreateBuiltinUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc,
Expr *InputArg);

View File

@ -878,6 +878,8 @@ namespace clang {
EXPR_BLOCK,
/// \brief A BlockDeclRef record.
EXPR_BLOCK_DECL_REF,
/// \brief A GenericSelectionExpr record.
EXPR_GENERIC_SELECTION,
// Objective-C

View File

@ -35,18 +35,16 @@ using namespace clang;
/// but also int expressions which are produced by things like comparisons in
/// C.
bool Expr::isKnownToHaveBooleanValue() const {
const Expr *E = IgnoreParens();
// If this value has _Bool type, it is obvious 0/1.
if (getType()->isBooleanType()) return true;
if (E->getType()->isBooleanType()) return true;
// If this is a non-scalar-integer type, we don't care enough to try.
if (!getType()->isIntegralOrEnumerationType()) return false;
if (!E->getType()->isIntegralOrEnumerationType()) return false;
if (const ParenExpr *PE = dyn_cast<ParenExpr>(this))
return PE->getSubExpr()->isKnownToHaveBooleanValue();
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(this)) {
if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
case UO_Plus:
case UO_Extension:
return UO->getSubExpr()->isKnownToHaveBooleanValue();
default:
return false;
@ -55,10 +53,10 @@ bool Expr::isKnownToHaveBooleanValue() const {
// Only look through implicit casts. If the user writes
// '(int) (a && b)' treat it as an arbitrary int.
if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(this))
if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E))
return CE->getSubExpr()->isKnownToHaveBooleanValue();
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(this)) {
if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
default: return false;
case BO_LT: // Relational operators.
@ -84,7 +82,7 @@ bool Expr::isKnownToHaveBooleanValue() const {
}
}
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(this))
if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E))
return CO->getTrueExpr()->isKnownToHaveBooleanValue() &&
CO->getFalseExpr()->isKnownToHaveBooleanValue();
@ -1363,6 +1361,9 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->
isUnusedResultAWarning(Loc, R1, R2, Ctx);
case GenericSelectionExprClass:
return cast<GenericSelectionExpr>(this)->getResultExpr()->
isUnusedResultAWarning(Loc, R1, R2, Ctx);
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
@ -1573,21 +1574,20 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1,
/// isOBJCGCCandidate - Check if an expression is objc gc'able.
/// returns true, if it is; false otherwise.
bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
switch (getStmtClass()) {
const Expr *E = IgnoreParens();
switch (E->getStmtClass()) {
default:
return false;
case ObjCIvarRefExprClass:
return true;
case Expr::UnaryOperatorClass:
return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case ImplicitCastExprClass:
return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case CStyleCastExprClass:
return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx);
return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx);
case DeclRefExprClass: {
const Decl *D = cast<DeclRefExpr>(this)->getDecl();
const Decl *D = cast<DeclRefExpr>(E)->getDecl();
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (VD->hasGlobalStorage())
return true;
@ -1600,11 +1600,11 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const {
return false;
}
case MemberExprClass: {
const MemberExpr *M = cast<MemberExpr>(this);
const MemberExpr *M = cast<MemberExpr>(E);
return M->getBase()->isOBJCGCCandidate(Ctx);
}
case ArraySubscriptExprClass:
return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx);
return cast<ArraySubscriptExpr>(E)->getBase()->isOBJCGCCandidate(Ctx);
}
}
@ -1827,6 +1827,11 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
return CT_Dependent;
return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C);
case GenericSelectionExprClass:
if (cast<GenericSelectionExpr>(this)->isResultDependent())
return CT_Dependent;
return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C);
// Some expressions are always dependent.
case DependentScopeDeclRefExprClass:
case CXXUnresolvedConstructExprClass:
@ -1853,6 +1858,12 @@ Expr* Expr::IgnoreParens() {
continue;
}
}
if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
if (!P->isResultDependent()) {
E = P->getResultExpr();
continue;
}
}
return E;
}
}
@ -1876,6 +1887,12 @@ Expr *Expr::IgnoreParenCasts() {
continue;
}
}
if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
if (!P->isResultDependent()) {
E = P->getResultExpr();
continue;
}
}
return E;
}
}
@ -1900,6 +1917,11 @@ Expr *Expr::IgnoreParenLValueCasts() {
E = P->getSubExpr();
continue;
}
} else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
if (!P->isResultDependent()) {
E = P->getResultExpr();
continue;
}
}
break;
}
@ -1923,6 +1945,12 @@ Expr *Expr::IgnoreParenImpCasts() {
continue;
}
}
if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
if (!P->isResultDependent()) {
E = P->getResultExpr();
continue;
}
}
return E;
}
}
@ -1965,6 +1993,13 @@ Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) {
}
}
if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) {
if (!P->isResultDependent()) {
E = P->getResultExpr();
continue;
}
}
return E;
}
}
@ -2156,6 +2191,11 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef) const {
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()
->isConstantInitializer(Ctx, IsForRef);
case GenericSelectionExprClass:
if (cast<GenericSelectionExpr>(this)->isResultDependent())
return false;
return cast<GenericSelectionExpr>(this)->getResultExpr()
->isConstantInitializer(Ctx, IsForRef);
case ChooseExprClass:
return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)
->isConstantInitializer(Ctx, IsForRef);
@ -2242,6 +2282,9 @@ Expr::isNullPointerConstant(ASTContext &Ctx,
// Accept ((void*)0) as a null pointer constant, as many other
// implementations do.
return PE->getSubExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const GenericSelectionExpr *GE =
dyn_cast<GenericSelectionExpr>(this)) {
return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC);
} else if (const CXXDefaultArgExpr *DefaultArg
= dyn_cast<CXXDefaultArgExpr>(this)) {
// See through default argument expressions
@ -2640,6 +2683,51 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs,
memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs);
}
GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
unsigned NumAssocs, SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack,
unsigned ResultIndex)
: Expr(GenericSelectionExprClass,
AssocExprs[ResultIndex]->getType(),
AssocExprs[ResultIndex]->getValueKind(),
AssocExprs[ResultIndex]->getObjectKind(),
AssocExprs[ResultIndex]->isTypeDependent(),
AssocExprs[ResultIndex]->isValueDependent(),
ContainsUnexpandedParameterPack),
AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
RParenLoc(RParenLoc) {
SubExprs[CONTROLLING] = ControllingExpr;
std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
}
GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context,
SourceLocation GenericLoc, Expr *ControllingExpr,
TypeSourceInfo **AssocTypes, Expr **AssocExprs,
unsigned NumAssocs, SourceLocation DefaultLoc,
SourceLocation RParenLoc,
bool ContainsUnexpandedParameterPack)
: Expr(GenericSelectionExprClass,
Context.DependentTy,
VK_RValue,
OK_Ordinary,
/*isTypeDependent=*/ true,
/*isValueDependent=*/ true,
ContainsUnexpandedParameterPack),
AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]),
SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs),
ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc),
RParenLoc(RParenLoc) {
SubExprs[CONTROLLING] = ControllingExpr;
std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes);
std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR);
}
//===----------------------------------------------------------------------===//
// DesignatedInitExpr
//===----------------------------------------------------------------------===//

View File

@ -233,6 +233,14 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
case Expr::ParenExprClass:
return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr());
// C1X 6.5.1.1p4: [A generic selection] is an lvalue, a function designator,
// or a void expression if its result expression is, respectively, an
// lvalue, a function designator, or a void expression.
case Expr::GenericSelectionExprClass:
if (cast<GenericSelectionExpr>(E)->isResultDependent())
return Cl::CL_PRValue;
return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr());
case Expr::BinaryOperatorClass:
case Expr::CompoundAssignOperatorClass:
// C doesn't have any binary expressions that are lvalues.

View File

@ -274,6 +274,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
bool VisitDeclRefExpr(DeclRefExpr *E) {
if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified())
return true;
@ -372,6 +375,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
bool VisitDeclRefExpr(DeclRefExpr *E);
bool VisitPredefinedExpr(PredefinedExpr *E) { return Success(E); }
bool VisitCompoundLiteralExpr(CompoundLiteralExpr *E);
@ -501,6 +507,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
bool VisitBinaryOperator(const BinaryOperator *E);
bool VisitCastExpr(CastExpr* E);
@ -717,6 +726,8 @@ namespace {
APValue VisitParenExpr(ParenExpr *E)
{ return Visit(E->getSubExpr()); }
APValue VisitGenericSelectionExpr(GenericSelectionExpr *E)
{ return Visit(E->getResultExpr()); }
APValue VisitUnaryExtension(const UnaryOperator *E)
{ return Visit(E->getSubExpr()); }
APValue VisitUnaryPlus(const UnaryOperator *E)
@ -975,6 +986,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
bool VisitIntegerLiteral(const IntegerLiteral *E) {
return Success(E->getValue(), E);
@ -1918,6 +1932,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
bool VisitCallExpr(const CallExpr *E);
bool VisitUnaryOperator(const UnaryOperator *E);
@ -2251,6 +2268,9 @@ public:
}
bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); }
bool VisitGenericSelectionExpr(GenericSelectionExpr *E) {
return Visit(E->getResultExpr());
}
bool VisitImaginaryLiteral(ImaginaryLiteral *E);
@ -2839,6 +2859,8 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
case Expr::ParenExprClass:
return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
case Expr::GenericSelectionExprClass:
return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx);
case Expr::IntegerLiteralClass:
case Expr::CharacterLiteralClass:
case Expr::CXXBoolLiteralExprClass:

View File

@ -1750,6 +1750,7 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
case Expr::ChooseExprClass:
case Expr::CompoundLiteralExprClass:
case Expr::ExtVectorElementExprClass:
case Expr::GenericSelectionExprClass:
case Expr::ObjCEncodeExprClass:
case Expr::ObjCIsaExprClass:
case Expr::ObjCIvarRefExprClass:

View File

@ -737,6 +737,23 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
PrintExpr(Node->getArgumentExpr());
}
}
void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) {
OS << "_Generic(";
PrintExpr(Node->getControllingExpr());
for (unsigned i = 0; i != Node->getNumAssocs(); ++i) {
OS << ", ";
QualType T = Node->getAssocType(i);
if (T.isNull())
OS << "default";
else
OS << T.getAsString(Policy);
OS << ": ";
PrintExpr(Node->getAssocExpr(i));
}
OS << ")";
}
void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) {
PrintExpr(Node->getLHS());
OS << "[";

View File

@ -434,6 +434,18 @@ void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) {
ID.AddBoolean(S->isConstQualAdded());
}
void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) {
VisitExpr(S);
for (unsigned i = 0; i != S->getNumAssocs(); ++i) {
QualType T = S->getAssocType(i);
if (T.isNull())
ID.AddPointer(0);
else
VisitType(T);
VisitExpr(S->getAssocExpr(i));
}
}
static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {

View File

@ -239,10 +239,7 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E,
llvm::SmallVector<SubobjectAdjustment, 2> Adjustments;
while (true) {
if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) {
E = PE->getSubExpr();
continue;
}
E = E->IgnoreParens();
if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
if ((CE->getCastKind() == CK_DerivedToBase ||
@ -545,6 +542,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
case Expr::DeclRefExprClass:
return EmitDeclRefLValue(cast<DeclRefExpr>(E));
case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
case Expr::GenericSelectionExprClass:
return EmitLValue(cast<GenericSelectionExpr>(E)->getResultExpr());
case Expr::PredefinedExprClass:
return EmitPredefinedLValue(cast<PredefinedExpr>(E));
case Expr::StringLiteralClass:
@ -1099,6 +1098,12 @@ static void setObjCGCLValueClass(const ASTContext &Ctx, const Expr *E,
}
return;
}
if (const GenericSelectionExpr *Exp = dyn_cast<GenericSelectionExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getResultExpr(), LV);
return;
}
if (const ImplicitCastExpr *Exp = dyn_cast<ImplicitCastExpr>(E)) {
setObjCGCLValueClass(Ctx, Exp->getSubExpr(), LV);
return;

View File

@ -81,6 +81,9 @@ public:
CGF.ErrorUnsupported(S, "aggregate expression");
}
void VisitParenExpr(ParenExpr *PE) { Visit(PE->getSubExpr()); }
void VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
Visit(GE->getResultExpr());
}
void VisitUnaryExtension(UnaryOperator *E) { Visit(E->getSubExpr()); }
// l-values.
@ -518,9 +521,8 @@ void AggExprEmitter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) {
/// zero to memory, return true. This can return false if uncertain, so it just
/// handles simple cases.
static bool isSimpleZero(const Expr *E, CodeGenFunction &CGF) {
// (0)
if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
return isSimpleZero(PE->getSubExpr(), CGF);
E = E->IgnoreParens();
// 0
if (const IntegerLiteral *IL = dyn_cast<IntegerLiteral>(E))
return IL->getValue() == 0;
@ -743,8 +745,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
/// non-zero bytes that will be stored when outputting the initializer for the
/// specified initializer expression.
static uint64_t GetNumNonZeroBytesInInit(const Expr *E, CodeGenFunction &CGF) {
if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
return GetNumNonZeroBytesInInit(PE->getSubExpr(), CGF);
E = E->IgnoreParens();
// 0 and 0.0 won't require any non-zero stores!
if (isSimpleZero(E, CGF)) return 0;

View File

@ -108,6 +108,9 @@ public:
}
ComplexPairTy VisitExpr(Expr *S);
ComplexPairTy VisitParenExpr(ParenExpr *PE) { return Visit(PE->getSubExpr());}
ComplexPairTy VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}
ComplexPairTy VisitImaginaryLiteral(const ImaginaryLiteral *IL);
// l-values.

View File

@ -457,6 +457,10 @@ public:
return Visit(PE->getSubExpr());
}
llvm::Constant *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}
llvm::Constant *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) {
return Visit(E->getInitializer());
}

View File

@ -163,6 +163,9 @@ public:
Value *VisitParenExpr(ParenExpr *PE) {
return Visit(PE->getSubExpr());
}
Value *VisitGenericSelectionExpr(GenericSelectionExpr *GE) {
return Visit(GE->getResultExpr());
}
// Leaves.
Value *VisitIntegerLiteral(const IntegerLiteral *E) {
@ -2396,8 +2399,7 @@ Value *ScalarExprEmitter::VisitBinComma(const BinaryOperator *E) {
/// flow into selects in some cases.
static bool isCheapEnoughToEvaluateUnconditionally(const Expr *E,
CodeGenFunction &CGF) {
if (const ParenExpr *PE = dyn_cast<ParenExpr>(E))
return isCheapEnoughToEvaluateUnconditionally(PE->getSubExpr(), CGF);
E = E->IgnoreParens();
// TODO: Allow anything we can constant fold to an integer or fp constant.
if (isa<IntegerLiteral>(E) || isa<CharacterLiteral>(E) ||

View File

@ -469,8 +469,7 @@ ConstantFoldsToSimpleInteger(const Expr *Cond, llvm::APInt &ResultInt) {
void CodeGenFunction::EmitBranchOnBoolExpr(const Expr *Cond,
llvm::BasicBlock *TrueBlock,
llvm::BasicBlock *FalseBlock) {
if (const ParenExpr *PE = dyn_cast<ParenExpr>(Cond))
return EmitBranchOnBoolExpr(PE->getSubExpr(), TrueBlock, FalseBlock);
Cond = Cond->IgnoreParens();
if (const BinaryOperator *CondBOp = dyn_cast<BinaryOperator>(Cond)) {
// Handle X && Y in a condition.

View File

@ -548,6 +548,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
.Case("cxx_exceptions", LangOpts.Exceptions)
.Case("cxx_rtti", LangOpts.RTTI)
.Case("enumerator_attributes", true)
.Case("generic_selections", true)
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
.Case("ownership_holds", true)

View File

@ -465,6 +465,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// [C++] boolean-literal [C++ 2.13.5]
/// [C++0x] 'nullptr' [C++0x 2.14.7]
/// '(' expression ')'
/// [C1X] generic-selection
/// '__func__' [C99 6.4.2.2]
/// [GNU] '__FUNCTION__'
/// [GNU] '__PRETTY_FUNCTION__'
@ -731,6 +732,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::wide_string_literal:
Res = ParseStringLiteralExpression();
break;
case tok::kw__Generic: // primary-expression: generic-selection [C1X 6.5.1]
Res = ParseGenericSelectionExpression();
break;
case tok::kw___builtin_va_arg:
case tok::kw___builtin_offsetof:
case tok::kw___builtin_choose_expr:
@ -1802,6 +1806,100 @@ ExprResult Parser::ParseStringLiteralExpression() {
return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size());
}
/// ParseGenericSelectionExpression - Parse a C1X generic-selection
/// [C1X 6.5.1.1].
///
/// generic-selection:
/// _Generic ( assignment-expression , generic-assoc-list )
/// generic-assoc-list:
/// generic-association
/// generic-assoc-list , generic-association
/// generic-association:
/// type-name : assignment-expression
/// default : assignment-expression
ExprResult Parser::ParseGenericSelectionExpression() {
assert(Tok.is(tok::kw__Generic) && "_Generic keyword expected");
SourceLocation KeyLoc = ConsumeToken();
if (!getLang().C1X)
Diag(KeyLoc, diag::ext_c1x_generic_selection);
SourceLocation LParenLoc = Tok.getLocation();
if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen, ""))
return ExprError();
ExprResult ControllingExpr;
{
// C1X 6.5.1.1p3 "The controlling expression of a generic selection is
// not evaluated."
EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated);
ControllingExpr = ParseAssignmentExpression();
if (ControllingExpr.isInvalid()) {
SkipUntil(tok::r_paren);
return ExprError();
}
}
if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "")) {
SkipUntil(tok::r_paren);
return ExprError();
}
SourceLocation DefaultLoc;
TypeVector Types(Actions);
ExprVector Exprs(Actions);
while (1) {
ParsedType Ty;
if (Tok.is(tok::kw_default)) {
// C1X 6.5.1.1p2 "A generic selection shall have no more than one default
// generic association."
if (!DefaultLoc.isInvalid()) {
Diag(Tok, diag::err_duplicate_default_assoc);
Diag(DefaultLoc, diag::note_previous_default_assoc);
SkipUntil(tok::r_paren);
return ExprError();
}
DefaultLoc = ConsumeToken();
Ty = ParsedType();
} else {
ColonProtectionRAIIObject X(*this);
TypeResult TR = ParseTypeName();
if (TR.isInvalid()) {
SkipUntil(tok::r_paren);
return ExprError();
}
Ty = TR.release();
}
Types.push_back(Ty);
if (ExpectAndConsume(tok::colon, diag::err_expected_colon, "")) {
SkipUntil(tok::r_paren);
return ExprError();
}
// FIXME: These expressions should be parsed in a potentially potentially
// evaluated context.
ExprResult ER(ParseAssignmentExpression());
if (ER.isInvalid()) {
SkipUntil(tok::r_paren);
return ExprError();
}
Exprs.push_back(ER.release());
if (Tok.isNot(tok::comma))
break;
ConsumeToken();
}
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
if (RParenLoc.isInvalid())
return ExprError();
return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
ControllingExpr.release(),
move_arg(Types), move_arg(Exprs));
}
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
///
/// argument-expression-list:

View File

@ -905,6 +905,8 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
if (E->isTypeDependent() || E->isValueDependent())
return false;
E = E->IgnoreParens();
switch (E->getStmtClass()) {
case Stmt::BinaryConditionalOperatorClass:
case Stmt::ConditionalOperatorClass: {
@ -927,11 +929,6 @@ bool Sema::SemaCheckStringLiteral(const Expr *E, const CallExpr *TheCall,
goto tryAgain;
}
case Stmt::ParenExprClass: {
E = cast<ParenExpr>(E)->getSubExpr();
goto tryAgain;
}
case Stmt::OpaqueValueExprClass:
if (const Expr *src = cast<OpaqueValueExpr>(E)->getSourceExpr()) {
E = src;
@ -1897,14 +1894,12 @@ static Expr *EvalAddr(Expr *E, llvm::SmallVectorImpl<DeclRefExpr *> &refVars) {
E->getType()->isObjCQualifiedIdType()) &&
"EvalAddr only works on pointers");
E = E->IgnoreParens();
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
switch (E->getStmtClass()) {
case Stmt::ParenExprClass:
// Ignore parentheses.
return EvalAddr(cast<ParenExpr>(E)->getSubExpr(), refVars);
case Stmt::DeclRefExprClass: {
DeclRefExpr *DR = cast<DeclRefExpr>(E);
@ -2034,6 +2029,8 @@ do {
// Our "symbolic interpreter" is just a dispatch off the currently
// viewed AST node. We then recursively traverse the AST by calling
// EvalAddr and EvalVal appropriately.
E = E->IgnoreParens();
switch (E->getStmtClass()) {
case Stmt::ImplicitCastExprClass: {
ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
@ -2067,12 +2064,6 @@ do {
return NULL;
}
case Stmt::ParenExprClass: {
// Ignore parentheses.
E = cast<ParenExpr>(E)->getSubExpr();
continue;
}
case Stmt::UnaryOperatorClass: {
// The only unary operator that make sense to handle here
// is Deref. All others don't resolve to a "name." This includes
@ -3272,11 +3263,9 @@ static void CheckArrayAccess_Check(Sema &S,
}
void Sema::CheckArrayAccess(const Expr *expr) {
while (true)
while (true) {
expr = expr->IgnoreParens();
switch (expr->getStmtClass()) {
case Stmt::ParenExprClass:
expr = cast<ParenExpr>(expr)->getSubExpr();
continue;
case Stmt::ArraySubscriptExprClass:
CheckArrayAccess_Check(*this, cast<ArraySubscriptExpr>(expr));
return;
@ -3291,4 +3280,5 @@ void Sema::CheckArrayAccess(const Expr *expr) {
default:
return;
}
}
}

View File

@ -748,6 +748,163 @@ QualType Sema::UsualArithmeticConversions(ExprResult &lhsExpr, ExprResult &rhsEx
//===----------------------------------------------------------------------===//
ExprResult
Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
MultiTypeArg types,
MultiExprArg exprs) {
unsigned NumAssocs = types.size();
assert(NumAssocs == exprs.size());
ParsedType *ParsedTypes = types.release();
Expr **Exprs = exprs.release();
TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs];
for (unsigned i = 0; i < NumAssocs; ++i) {
if (ParsedTypes[i])
(void) GetTypeFromParser(ParsedTypes[i], &Types[i]);
else
Types[i] = 0;
}
ExprResult ER = CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
ControllingExpr, Types, Exprs,
NumAssocs);
delete Types;
return ER;
}
ExprResult
Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
TypeSourceInfo **Types,
Expr **Exprs,
unsigned NumAssocs) {
bool TypeErrorFound = false,
IsResultDependent = ControllingExpr->isTypeDependent(),
ContainsUnexpandedParameterPack
= ControllingExpr->containsUnexpandedParameterPack();
for (unsigned i = 0; i < NumAssocs; ++i) {
if (Exprs[i]->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
if (Types[i]) {
if (Types[i]->getType()->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
if (Types[i]->getType()->isDependentType()) {
IsResultDependent = true;
} else {
// C1X 6.5.1.1p2 "The type name in a generic association shall specify a
// complete object type other than a variably modified type."
unsigned D = 0;
if (Types[i]->getType()->isIncompleteType())
D = diag::err_assoc_type_incomplete;
else if (!Types[i]->getType()->isObjectType())
D = diag::err_assoc_type_nonobject;
else if (Types[i]->getType()->isVariablyModifiedType())
D = diag::err_assoc_type_variably_modified;
if (D != 0) {
Diag(Types[i]->getTypeLoc().getBeginLoc(), D)
<< Types[i]->getTypeLoc().getSourceRange()
<< Types[i]->getType();
TypeErrorFound = true;
}
// C1X 6.5.1.1p2 "No two generic associations in the same generic
// selection shall specify compatible types."
for (unsigned j = i+1; j < NumAssocs; ++j)
if (Types[j] && !Types[j]->getType()->isDependentType() &&
Context.typesAreCompatible(Types[i]->getType(),
Types[j]->getType())) {
Diag(Types[j]->getTypeLoc().getBeginLoc(),
diag::err_assoc_compatible_types)
<< Types[j]->getTypeLoc().getSourceRange()
<< Types[j]->getType()
<< Types[i]->getType();
Diag(Types[i]->getTypeLoc().getBeginLoc(),
diag::note_compat_assoc)
<< Types[i]->getTypeLoc().getSourceRange()
<< Types[i]->getType();
TypeErrorFound = true;
}
}
}
}
if (TypeErrorFound)
return ExprError();
// If we determined that the generic selection is result-dependent, don't
// try to compute the result expression.
if (IsResultDependent)
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
Types, Exprs, NumAssocs, DefaultLoc,
RParenLoc, ContainsUnexpandedParameterPack));
llvm::SmallVector<unsigned, 1> CompatIndices;
unsigned DefaultIndex = -1U;
for (unsigned i = 0; i < NumAssocs; ++i) {
if (!Types[i])
DefaultIndex = i;
else if (Context.typesAreCompatible(ControllingExpr->getType(),
Types[i]->getType()))
CompatIndices.push_back(i);
}
// C1X 6.5.1.1p2 "The controlling expression of a generic selection shall have
// type compatible with at most one of the types named in its generic
// association list."
if (CompatIndices.size() > 1) {
// We strip parens here because the controlling expression is typically
// parenthesized in macro definitions.
ControllingExpr = ControllingExpr->IgnoreParens();
Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_multi_match)
<< ControllingExpr->getSourceRange() << ControllingExpr->getType()
<< (unsigned) CompatIndices.size();
for (llvm::SmallVector<unsigned, 1>::iterator I = CompatIndices.begin(),
E = CompatIndices.end(); I != E; ++I) {
Diag(Types[*I]->getTypeLoc().getBeginLoc(),
diag::note_compat_assoc)
<< Types[*I]->getTypeLoc().getSourceRange()
<< Types[*I]->getType();
}
return ExprError();
}
// C1X 6.5.1.1p2 "If a generic selection has no default generic association,
// its controlling expression shall have type compatible with exactly one of
// the types named in its generic association list."
if (DefaultIndex == -1U && CompatIndices.size() == 0) {
// We strip parens here because the controlling expression is typically
// parenthesized in macro definitions.
ControllingExpr = ControllingExpr->IgnoreParens();
Diag(ControllingExpr->getLocStart(), diag::err_generic_sel_no_match)
<< ControllingExpr->getSourceRange() << ControllingExpr->getType();
return ExprError();
}
// C1X 6.5.1.1p3 "If a generic selection has a generic association with a
// type name that is compatible with the type of the controlling expression,
// then the result expression of the generic selection is the expression
// in that generic association. Otherwise, the result expression of the
// generic selection is the expression in the default generic association."
unsigned ResultIndex =
CompatIndices.size() ? CompatIndices[0] : DefaultIndex;
return Owned(new (Context) GenericSelectionExpr(
Context, KeyLoc, ControllingExpr,
Types, Exprs, NumAssocs, DefaultLoc,
RParenLoc, ContainsUnexpandedParameterPack,
ResultIndex));
}
/// ActOnStringLiteral - The specified tokens were lexed as pasted string
/// fragments (e.g. "foo" "bar" L"baz"). The result string has to handle string
/// concatenation ([C99 5.1.1.2, translation phase #6]), so it may come from

View File

@ -1602,6 +1602,22 @@ public:
RParenLoc);
}
/// \brief Build a new generic selection expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildGenericSelectionExpr(SourceLocation KeyLoc,
SourceLocation DefaultLoc,
SourceLocation RParenLoc,
Expr *ControllingExpr,
TypeSourceInfo **Types,
Expr **Exprs,
unsigned NumAssocs) {
return getSema().CreateGenericSelectionExpr(KeyLoc, DefaultLoc, RParenLoc,
ControllingExpr, Types, Exprs,
NumAssocs);
}
/// \brief Build a new overloaded operator call expression.
///
/// By default, performs semantic analysis to build the new expression.
@ -5523,6 +5539,42 @@ TreeTransform<Derived>::TransformCharacterLiteral(CharacterLiteral *E) {
return SemaRef.Owned(E);
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) {
ExprResult ControllingExpr =
getDerived().TransformExpr(E->getControllingExpr());
if (ControllingExpr.isInvalid())
return ExprError();
llvm::SmallVector<Expr *, 4> AssocExprs;
llvm::SmallVector<TypeSourceInfo *, 4> AssocTypes;
for (unsigned i = 0; i != E->getNumAssocs(); ++i) {
TypeSourceInfo *TS = E->getAssocTypeSourceInfo(i);
if (TS) {
TypeSourceInfo *AssocType = getDerived().TransformType(TS);
if (!AssocType)
return ExprError();
AssocTypes.push_back(AssocType);
} else {
AssocTypes.push_back(0);
}
ExprResult AssocExpr = getDerived().TransformExpr(E->getAssocExpr(i));
if (AssocExpr.isInvalid())
return ExprError();
AssocExprs.push_back(AssocExpr.release());
}
return getDerived().RebuildGenericSelectionExpr(E->getGenericLoc(),
E->getDefaultLoc(),
E->getRParenLoc(),
ControllingExpr.release(),
AssocTypes.data(),
AssocExprs.data(),
E->getNumAssocs());
}
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) {

View File

@ -122,6 +122,7 @@ namespace clang {
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
void VisitBlockExpr(BlockExpr *E);
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
void VisitGenericSelectionExpr(GenericSelectionExpr *E);
void VisitObjCStringLiteral(ObjCStringLiteral *E);
void VisitObjCEncodeExpr(ObjCEncodeExpr *E);
void VisitObjCSelectorExpr(ObjCSelectorExpr *E);
@ -822,6 +823,25 @@ void ASTStmtReader::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
E->setConstQualAdded(Record[Idx++]);
}
void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
VisitExpr(E);
E->NumAssocs = Record[Idx++];
E->AssocTypes = new (*Reader.getContext()) TypeSourceInfo*[E->NumAssocs];
E->SubExprs =
new(*Reader.getContext()) Stmt*[GenericSelectionExpr::END_EXPR+E->NumAssocs];
E->SubExprs[GenericSelectionExpr::CONTROLLING] = Reader.ReadSubExpr();
for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
E->AssocTypes[I] = GetTypeSourceInfo(Record, Idx);
E->SubExprs[GenericSelectionExpr::END_EXPR+I] = Reader.ReadSubExpr();
}
E->ResultIndex = Record[Idx++];
E->GenericLoc = ReadSourceLocation(Record, Idx);
E->DefaultLoc = ReadSourceLocation(Record, Idx);
E->RParenLoc = ReadSourceLocation(Record, Idx);
}
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements
@ -1696,6 +1716,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
S = new (Context) BlockDeclRefExpr(Empty);
break;
case EXPR_GENERIC_SELECTION:
S = new (Context) GenericSelectionExpr(Empty);
break;
case EXPR_OBJC_STRING_LITERAL:
S = new (Context) ObjCStringLiteral(Empty);
break;

View File

@ -659,6 +659,7 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream,
RECORD(EXPR_SHUFFLE_VECTOR);
RECORD(EXPR_BLOCK);
RECORD(EXPR_BLOCK_DECL_REF);
RECORD(EXPR_GENERIC_SELECTION);
RECORD(EXPR_OBJC_STRING_LITERAL);
RECORD(EXPR_OBJC_ENCODE);
RECORD(EXPR_OBJC_SELECTOR_EXPR);

View File

@ -93,6 +93,7 @@ namespace clang {
void VisitShuffleVectorExpr(ShuffleVectorExpr *E);
void VisitBlockExpr(BlockExpr *E);
void VisitBlockDeclRefExpr(BlockDeclRefExpr *E);
void VisitGenericSelectionExpr(GenericSelectionExpr *E);
// Objective-C Expressions
void VisitObjCStringLiteral(ObjCStringLiteral *E);
@ -785,6 +786,23 @@ void ASTStmtWriter::VisitBlockDeclRefExpr(BlockDeclRefExpr *E) {
Code = serialization::EXPR_BLOCK_DECL_REF;
}
void ASTStmtWriter::VisitGenericSelectionExpr(GenericSelectionExpr *E) {
VisitExpr(E);
Record.push_back(E->getNumAssocs());
Writer.AddStmt(E->getControllingExpr());
for (unsigned I = 0, N = E->getNumAssocs(); I != N; ++I) {
Writer.AddTypeSourceInfo(E->getAssocTypeSourceInfo(I), Record);
Writer.AddStmt(E->getAssocExpr(I));
}
Record.push_back(E->isResultDependent() ? -1U : E->getResultIndex());
Writer.AddSourceLocation(E->getGenericLoc(), Record);
Writer.AddSourceLocation(E->getDefaultLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
Code = serialization::EXPR_GENERIC_SELECTION;
}
//===----------------------------------------------------------------------===//
// Objective-C Expressions and Statements.
//===----------------------------------------------------------------------===//

View File

@ -859,7 +859,8 @@ class EdgeBuilder {
default:
break;
case Stmt::ParenExprClass:
S = cast<ParenExpr>(S)->IgnoreParens();
case Stmt::GenericSelectionExprClass:
S = cast<Expr>(S)->IgnoreParens();
firstCharOnly = true;
continue;
case Stmt::BinaryConditionalOperatorClass:

View File

@ -41,6 +41,10 @@ SVal Environment::getSVal(const Stmt *E, SValBuilder& svalBuilder) const {
// ParenExprs are no-ops.
E = cast<ParenExpr>(E)->getSubExpr();
continue;
case Stmt::GenericSelectionExprClass:
// GenericSelectionExprs are no-ops.
E = cast<GenericSelectionExpr>(E)->getResultExpr();
continue;
case Stmt::CharacterLiteralClass: {
const CharacterLiteral* C = cast<CharacterLiteral>(E);
return svalBuilder.makeIntVal(C->getValue(), C->getType());

View File

@ -458,6 +458,8 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
case Stmt::ParenExprClass:
llvm_unreachable("ParenExprs already handled.");
case Stmt::GenericSelectionExprClass:
llvm_unreachable("GenericSelectionExprs already handled.");
// Cases that should never be evaluated simply because they shouldn't
// appear in the CFG.
case Stmt::BreakStmtClass:

View File

@ -93,3 +93,6 @@ choose_expr *int_ptr8 = &integer;
// ShuffleVectorExpr
shuffle_expr *vec_ptr = &vec2;
// GenericSelectionExpr
generic_selection_expr *double_ptr6 = &floating;

View File

@ -99,3 +99,7 @@ typedef typeof(__builtin_choose_expr(17 > 19, d0, 1)) choose_expr;
// ShuffleVectorExpr
typedef typeof(__builtin_shufflevector(vec2, vec2b, 2, 1)) shuffle_expr;
// GenericSelectionExpr
typedef typeof(_Generic(i, char*: 0, int: 0., default: hello))
generic_selection_expr;

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s
void foo(void) {
_Generic; // expected-error {{expected '('}}
(void) _Generic(0); // expected-error {{expected ','}}
(void) _Generic(0, void); // expected-error {{expected ':'}}
(void) _Generic(0,
default: 0, // expected-note {{previous default generic association is here}}
default: 0); // expected-error {{duplicate default generic association}}
}

View File

@ -0,0 +1,26 @@
// RUN: %clang_cc1 -std=c1x -fsyntax-only -verify %s
void foo(int n) {
(void) _Generic(0,
struct A: 0, // expected-error {{type 'struct A' in generic association incomplete}}
void(): 0, // expected-error {{type 'void ()' in generic association not an object type}}
int[n]: 0); // expected-error {{type 'int [n]' in generic association is a variably modified type}}
(void) _Generic(0,
void (*)(): 0, // expected-note {{compatible type 'void (*)()' specified here}}
void (*)(void): 0); // expected-error {{type 'void (*)(void)' in generic association compatible with previously specified type 'void (*)()'}}
(void) _Generic((void (*)()) 0, // expected-error {{controlling expression type 'void (*)()' compatible with 2 generic association types}}
void (*)(int): 0, // expected-note {{compatible type 'void (*)(int)' specified here}}
void (*)(void): 0); // expected-note {{compatible type 'void (*)(void)' specified here}}
(void) _Generic(0, // expected-error {{controlling expression type 'int' not compatible with any generic association type}}
char: 0, short: 0, long: 0);
int a1[_Generic(0, int: 1, short: 2, float: 3, default: 4) == 1 ? 1 : -1];
int a2[_Generic(0, default: 1, short: 2, float: 3, int: 4) == 4 ? 1 : -1];
int a3[_Generic(0L, int: 1, short: 2, float: 3, default: 4) == 4 ? 1 : -1];
int a4[_Generic(0L, default: 1, short: 2, float: 3, int: 4) == 1 ? 1 : -1];
int a5[_Generic(0, int: 1, short: 2, float: 3) == 1 ? 1 : -1];
int a6[_Generic(0, short: 1, float: 2, int: 3) == 3 ? 1 : -1];
}

View File

@ -0,0 +1,46 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
template <typename T, typename U = void*>
struct A {
enum {
id = _Generic(T(), // expected-error {{controlling expression type 'char' not compatible with any generic association type}}
int: 1, // expected-note {{compatible type 'int' specified here}}
float: 2,
U: 3) // expected-error {{type 'int' in generic association compatible with previously specified type 'int'}}
};
};
static_assert(A<int>::id == 1, "fail");
static_assert(A<float>::id == 2, "fail");
static_assert(A<double, double>::id == 3, "fail");
A<char> a1; // expected-note {{in instantiation of template class 'A<char, void *>' requested here}}
A<short, int> a2; // expected-note {{in instantiation of template class 'A<short, int>' requested here}}
template <typename T, typename U>
struct B {
enum {
id = _Generic(T(),
int: 1, // expected-note {{compatible type 'int' specified here}}
int: 2, // expected-error {{type 'int' in generic association compatible with previously specified type 'int'}}
U: 3)
};
};
template <unsigned Arg, unsigned... Args> struct Or {
enum { result = Arg | Or<Args...>::result };
};
template <unsigned Arg> struct Or<Arg> {
enum { result = Arg };
};
template <class... Args> struct TypeMask {
enum {
result = Or<_Generic(Args(), int: 1, long: 2, short: 4, float: 8)...>::result
};
};
static_assert(TypeMask<int, long, short>::result == 7, "fail");
static_assert(TypeMask<float, short>::result == 12, "fail");
static_assert(TypeMask<int, float, float>::result == 9, "fail");

View File

@ -130,6 +130,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
case Stmt::AddrLabelExprClass:
case Stmt::StmtExprClass:
case Stmt::ChooseExprClass:
case Stmt::GenericSelectionExprClass:
case Stmt::GNUNullExprClass:
case Stmt::CXXStaticCastExprClass:
case Stmt::CXXDynamicCastExprClass: