зеркало из https://github.com/microsoft/clang.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@129554 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
7e7fbd05a5
Коммит
f111d93572
|
@ -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>
|
||||
<!-- ======================================================================= -->
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -1101,6 +1101,8 @@ private:
|
|||
|
||||
ExprResult ParseStringLiteralExpression();
|
||||
|
||||
ExprResult ParseGenericSelectionExpression();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// C++ Expressions
|
||||
ExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
|
||||
|
|
|
@ -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); }
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
126
lib/AST/Expr.cpp
126
lib/AST/Expr.cpp
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 << "[";
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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) ||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -93,3 +93,6 @@ choose_expr *int_ptr8 = &integer;
|
|||
|
||||
// ShuffleVectorExpr
|
||||
shuffle_expr *vec_ptr = &vec2;
|
||||
|
||||
// GenericSelectionExpr
|
||||
generic_selection_expr *double_ptr6 = &floating;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}}
|
||||
}
|
|
@ -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];
|
||||
}
|
|
@ -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");
|
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче