Skip to content

Commit

Permalink
C1X: implement generic selections
Browse files Browse the repository at this point in the history
As an extension, generic selection support has been added for all
supported languages.  The syntax is the same as for C1X.

llvm-svn: 129554
  • Loading branch information
pcc committed Apr 15, 2011
1 parent a686b5f commit 9114759
Show file tree
Hide file tree
Showing 40 changed files with 845 additions and 57 deletions.
15 changes: 15 additions & 0 deletions clang/docs/LanguageExtensions.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ <h1>Clang Language Extensions</h1>
<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>
Expand Down Expand Up @@ -603,6 +604,20 @@ <h2 id="overloading-in-c">Function Overloading in C</h2>
<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>
<!-- ======================================================================= -->
Expand Down
112 changes: 112 additions & 0 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3679,6 +3679,118 @@ class ParenListExpr : public Expr {
};


/// \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
//===----------------------------------------------------------------------===//
Expand Down
16 changes: 16 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,8 @@ class Parser : public CodeCompletionHandler {

ExprResult ParseStringLiteralExpression();

ExprResult ParseGenericSelectionExpression();

//===--------------------------------------------------------------------===//
// C++ Expressions
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
Expand Down
13 changes: 8 additions & 5 deletions clang/include/clang/Sema/Ownership.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand All @@ -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); }
Expand Down
14 changes: 14 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -2009,6 +2009,20 @@ class Sema {
/// 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);
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down

0 comments on commit 9114759

Please sign in to comment.